我目前正在Haskell上课,在理解如何将函数作为参数传递时遇到了一些麻烦。对于此任务,我们的任务是创建一个可评估表达式的程序。为了减少重复步骤,我想通过创建一个辅助函数来抽象该函数,该辅助函数将一个运算符作为输入并返回结果
主要功能:
--no-highlight
助手功能:
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
我不确定为什么会发生这种情况,因为我为函数赋予了Haskell定义的适当参数。任何帮助将不胜感激,因为我还是该语言的新手。
答案 0 :(得分:5)
现在,您的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
答案 1 :(得分:-2)
该错误告诉您不能在函数链中的一种类型内嵌套类型限定符。而是将所有限定符放在类型签名的开头:
evalOp:: (Num a) => EDict -> (a -> a -> a) -> Expr -> Expr -> Maybe Double
有关更详尽的讨论,请参见Haskell - Illegal Polymorphic type?。