假设我有一个函数:
f :: Int -> (Rational, Integer)
f b = ((toRational b)+1,(toInteger b)+1)
我想抽象掉(+1)这样:
f :: Int -> (Rational, Integer)
f b = (h (toRational b)
,h (toInteger b))
where h = (+1)
这显然不起作用,但如果我指定类型签名,它将起作用:
f :: Int -> (Rational, Integer)
f b = (h (toRational b)
,h (toInteger b))
where h :: Num a => a -> a
h = (+1)
假设我现在想通过传递h作为参数来进一步抽象函数:
f :: Num a => Int -> (a -> a) -> (Rational, Integer)
f b g = (h (toRational b)
,h (toInteger b))
where h :: Num a => a -> a
h = g
我得到一个错误,内部的a和外部的a不一样。
有人知道如何正确编写这个函数吗?我想把一个多态函数g
传递给f
,并以多态方式使用它。
我在不同的项目中多次遇到这种情况,但我找不到一个好的解决方案。
我找到了解决方案:使用像so这样的forall量词:
{-# LANGUAGE RankNTypes #-}
f :: Int -> (forall a. Num a=> a -> a) -> (Rational, Integer)
f b g = (h (toRational b)
,h (toInteger b))
where h :: Num a => a -> a
h = g
当然可以转化为:
f :: Int -> (forall a. Num a=>a -> a) -> (Rational, Integer)
f b g = (g (toRational b)
,g (toInteger b))