我正在'Haskell the hardway'之后尝试Haskell,而我仍然坚持理解基本类型系统。我有以下代码,并且haskell抱怨它无法处理该函数。
f3 :: Num -> Int -> Num
f3 x y = x + y
我接受它,它必须做一些currying或基本模型,其中haskell将f x y转换为(f x)y但是如果我想传递Int和Y,我能做到吗?如果我能怎么做呢?
答案 0 :(得分:5)
我接受它,它必须做一些currying或基本模型,其中haskell将f x y转换为(f x)y
没有。它几乎总是在Haskell世界中与类型有关。首先,Num
是类型类,而不是类型。类型可以是类型类的实例,例如Int
,Integer
和Double
是Num
的实例。现在,让我们来看看加号'类型:
(+) :: Num a => a -> a -> a
啊哈!它需要两个a
类型的参数,并返回a
,其中a
需要是Num
的实例(也称为约束)
现在我们有足够的信息来重温f3
:
f3_wrong_sig :: Num -> Int -> Num
在上面的讨论之后,很明显f3_wrong_sig
签名错误。它不是Num
,而是需要a
约束Num
:
f3_wrong_implementation :: Num a => a -> Int -> a
f3_wrong_implementation x y = x + y
但是,如果我们记住(+)
的类型,x + y
只能使a
和Int
等效(也可以写为a ~ Int
)。我们需要一种方法来从Int
创建另一个数字类型:我们需要一个函数Num a => Int -> a
。让我们检查GHCi中Int
的一些信息:
ghci> :i Int
data Int = GHC.Types.I# GHC.Prim.Int# -- Defined in `GHC.Types'
-- omitted
instance Integral Int -- Defined in `GHC.Real'
instance Num Int -- Defined in `GHC.Num'
-- omitted
Int
不仅是Num
的实例,也是Integral
的实例。快速hoogle search给了我们fromIntegral :: (Integral b, Num a) => b -> a
,我们可以插入并最终得到我们想要的内容:
f3 :: Num a => a -> Int -> a
f3 x y = x + fromIntegral y
此时,我们还可以采取最后一步,使其更加通用,因为fromIntegral
适用于任何 Integral
:
f3_general :: (Integral b, Num a) => a -> b -> a
f3_general x y = x + fromIntegral y
这也是GHC推断的类型。
答案 1 :(得分:1)
下一个原因:
1)没有Num
2)(+)
函数的两个参数必须具有相同类型
可能的解决方案:
f3 :: Int -> Int -> Int
f3 :: Double -> Double -> Double
f3 :: Num a => a -> a -> a -- could add any numerical type