Haskell中的抽象函数

jen*_*els 3 parameters haskell types function

我目前正在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
Run Code Online (Sandbox Code Playgroud)

辅助功能:

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
Run Code Online (Sandbox Code Playgroud)

其他定义

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
Run Code Online (Sandbox Code Playgroud)

我研究了如何将+,-和*传递给其他函数,并发现这些运算符由以下定义定义:

ghci> :t (*)
(*) :: (Num a) => a -> a -> a  
Run Code Online (Sandbox Code Playgroud)

但是,当我运行代码时,出现以下编译错误:

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
Run Code Online (Sandbox Code Playgroud)

我不确定为什么会发生这种情况,因为我为函数提供了Haskell定义的适当参数。任何帮助将不胜感激,因为我还是该语言的新手。

che*_*ner 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
Run Code Online (Sandbox Code Playgroud)

(+) :: Num a => a -> a -> a是的有效参数evalOp,因为其类型可以“限制”为Double -> Double -> Double

> let f :: Double -> Double -> Double; f = (+)
> f 3 5
8.0
Run Code Online (Sandbox Code Playgroud)

如果您的表达式类型已参数化,那么您将对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
Run Code Online (Sandbox Code Playgroud)