Функция абстрагирования в Haskell - PullRequest
3 голосов
/ 23 октября 2019

В настоящее время я учусь на уроке в Haskell, и у меня возникли проблемы с пониманием того, как функции передаются в качестве параметров. Для этого задания нам было поручено создать программу, которая будет оценивать выражения. Чтобы уменьшить покрытие котла, я хотел абстрагировать функцию, создав вспомогательную функцию, которая будет принимать оператор в качестве входа и возвращать результат

Основная функция:

eval :: EDict -> Expr -> Maybe Double
eval _ (Val x) = Just x
eval d (Var i) = find d i
eval d (Add x y) = evalOp d (+) x y
eval d (Mul x y) = evalOp d (*) x y
eval d (Sub x y) = evalOp d (-) x y

Вспомогательная функция:

evalOp:: EDict -> ((Num a) => a -> a -> a) -> Expr -> Expr -> Maybe Double
evalOp d op x y =
  let r = eval d x
      s = eval d y
  in case (r, s) of
    (Just m, Just n) -> Just (m `op` n)
    _                -> Nothing

Другие определения

data Expr
  = Val Double
  | Add Expr Expr
  | Mul Expr Expr
  | Sub Expr Expr
  | Dvd Expr Expr
  | Var Id
  | Def Id Expr Expr
  deriving (Eq, Show)

type Dict k d  =  [(k,d)]

define :: Dict k d -> k -> d -> Dict k d
define d s v = (s,v):d

find :: Eq k => Dict k d -> k -> Maybe d
find []             _                 =  Nothing
find ( (s,v) : ds ) name | name == s  =  Just v
                         | otherwise  =  find ds name

type EDict = Dict String Double

Я рассмотрел, как +, - и * должны передаваться в другие функции, и обнаружил, что эти операторы определены следующим определением:

ghci> :t (*)
(*) :: (Num a) => a -> a -> a  

Однако, когда я запускаю свой код, я получаю следующую ошибку компиляции:

Illegal polymorphic or qualified type: Num a => a -> a -> a
    Perhaps you intended to use RankNTypes or Rank2Types
    In the type signature for ‘evalOp’:
      evalOp :: EDict
                -> ((Num a) => a -> a -> a) -> Expr -> Expr -> Maybe Double

Я не совсем уверен, почему это происходит, поскольку я дал своей функции правильные параметры, как определеноХаскеллом. Любая помощь будет принята с благодарностью, так как я все еще плохо знаком с языком.

Ответы [ 2 ]

5 голосов
/ 23 октября 2019

Прямо сейчас ваш тип данных Expr ограничен Double -значными выражениями, поэтому нет необходимости иметь дело с полиморфизмом.

evalOp:: EDict -> (Double -> Double -> Double) -> Expr -> Expr -> Maybe Double
evalOp d op x y =
  let r = eval d x
      s = eval d y
  in case (r, s) of
    (Just m, Just n) -> Just (m `op` n)
    _                -> Nothing

(+) :: Num a => a -> a -> a является допустимым аргументом для evalOp, поскольку его тип может быть «ограничен» до Double -> Double -> Double.

> let f :: Double -> Double -> Double; f = (+)
> f 3 5
8.0

Если бы ваш тип выражения был параметризован, , тогда вы бы поставили ограничение Num aв ваших функциях (не только в аргументах, которые включают a, потому что вы хотите, чтобы во всей функции было одинаковое a).

data Expr a
  = Val a
  | Add (Expr a) (Expr a)
  | Mul (Expr a) (Expr a)
  | Sub (Expr a) (Expr a)
  | Dvd (Expr a) (Expr a)
  | Var Id
  | Def Id (Expr a) (Expr a)
  deriving (Eq, Show)

type EDict a = Dict String a

evalOp:: Num a => EDict a -> (a -> a -> a) -> Expr a -> Expr a -> Maybe a
evalOp d op x y =
  let r = eval d x
      s = eval d y
  in case (r, s) of
    (Just m, Just n) -> Just (m `op` n)
    _                -> Nothing


eval :: Num a => EDict a -> Expr a -> Maybe a
eval _ (Val x) = Just x
eval d (Var i) = find d i
eval d (Add x y) = evalOp d (+) x y
eval d (Mul x y) = evalOp d (*) x y
eval d (Sub x y) = evalOp d (-) x y
0 голосов
/ 23 октября 2019

Ошибка говорит вам, что вы не можете вложить спецификатор типа в один из типов в вашей цепочке функций. Вместо этого поместите все квалификаторы в начале сигнатуры типа:

evalOp:: (Num a) => EDict -> (a -> a -> a) -> Expr -> Expr -> Maybe Double

См. Haskell - Недопустимый полиморфный тип? для более подробного обсуждения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...