编写binop以使用int和float

Joh*_*ler 4 haskell typechecking

我有一个我正在研究的解析器.没有进入所有细节,我想要一个将添加两个数值的函数:

add [VFloat a, VFloat b] = return $ VFloat (a + b)
add [VInt   a, VFloat b] = return $ VFloat (fromInteger a + b)
add [VFloat a, VInt   b] = return $ VFloat (a + fromInteger b)
add [VInt   a, VInt   b] = return $ VInt   (a + b)
add [_,_] = throwError "Currently only adding numbers"
add _ = throwError "Arity Error: Add takes 2 arguments"
Run Code Online (Sandbox Code Playgroud)

很酷,很棒.现在,我想同样的功能-,*,/,<,>,==,等...

所以我把+操作员分解出来并转向操作员op :: Num a => a->a->a吗?

好吧不太好.如果我只需更换+'op'类型检查器告诉我,运算实际上是Double -> Double -> Double基于前三个版本,因此它不能被应用到Integer第四版本S.

两个问题:

  1. 如何编写binop :: Num a => (a->a->a) -> [Value]-> EvalM Value以便它可以处理VInt和VFloat?
  2. 我所面临的情况的正确名称是什么,以便我下次可以谷歌答案?

Dan*_*zer 5

这被称为更高级别的类型,基本上是您想要的类型

 binop :: (forall a. Num a => a -> a -> a) -> [Value] -> EvalM Value
Run Code Online (Sandbox Code Playgroud)

但你拥有的是什么

 binop :: forall a. Num a => (a -> a -> a) -> [Value] -> EvalM Value
Run Code Online (Sandbox Code Playgroud)

你看得到差别吗?对于第一个函数,运算符实际上是函数内的多态,它表示"给定一个函数可以采用任何Num a类型a -> a -> a......".第二个人说,"对于所有人来说a,给定一个任意的函数a -> a -> a......".

幸运的是GHC支持更高级别的类型,

{-# LANGUAGE RankNTypes #-}

...
binop :: (forall a. Num a => a -> a -> a) -> [Value] -> EvalM Value
binop (+) [VFloat a, VFloat b] = return $ VFloat (a + b)
binop (+) [VInt   a, VFloat b] = return $ VFloat (fromInteger a + b)
binop (+) [VFloat a, VInt   b] = return $ VFloat (a + fromInteger b)
binop (+) [VInt   a, VInt   b] = return $ VInt   (a + b)
binop  _  [_,_] = throwError "Currently only adding numbers"
binop  _  _     = throwError "Arity Error: Add takes 2 arguments"
Run Code Online (Sandbox Code Playgroud)

但是,类型推断器不具有更高级别类型的热量,因此您可能必须添加显式签名.