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.
两个问题:
binop :: Num a => (a->a->a) -> [Value]-> EvalM Value
以便它可以处理VInt和VFloat?这被称为更高级别的类型,基本上是您想要的类型
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)
但是,类型推断器不具有更高级别类型的热量,因此您可能必须添加显式签名.