为什么我不能在函数中混合两个原语?

时间:2014-09-18 04:44:31

标签: haskell

我正在'Haskell the hardway'之后尝试Haskell,而我仍然坚持理解基本类型系统。我有以下代码,并且haskell抱怨它无法处理该函数。

f3 :: Num -> Int -> Num
f3 x y = x + y

我接受它,它必须做一些currying或基本模型,其中haskell将f x y转换为(f x)y但是如果我想传递Int和Y,我能做到吗?如果我能怎么做呢?

2 个答案:

答案 0 :(得分:5)

  

我接受它,它必须做一些currying或基本模型,其中haskell将f x y转换为(f x)y

没有。它几乎总是在Haskell世界中与类型有关。首先,Num是类型类,而不是类型。类型可以是类型类的实例,例如IntIntegerDoubleNum的实例。现在,让我们来看看加号'类型:

(+) :: 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只能使aInt等效(也可以写为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