Haskell签名:基础知识

时间:2018-02-03 16:15:00

标签: haskell

为什么这不起作用?

sum :: (Num a, Num b) => a -> b -> c
sum a b = a + b

当然,错误信息与签名有关,但我仍然不明白原因。

Couldn't match expected type ‘a’ with actual type ‘b’
‘b’ is a rigid type variable bound by
  the type signature for:
    sum :: forall a b c. (Num a, Num b) => a -> b -> c

‘a’ is a rigid type variable bound by
  the type signature for:
    sum :: forall a b c. (Num a, Num b) => a -> b -> c

In the second argument of ‘(+)’, namely ‘b’
In the expression: a + b
In an equation for ‘sum’: sum a b = a + b

我错过了什么?

3 个答案:

答案 0 :(得分:8)

因为(+)函数具有签名:

(+) :: Num a => a -> a -> a

这意味着(+)函数要求操作数具有相同的类型,结果与操作数的类型相同。

您的签名意味着程序员可以选择任何Num类型作为第一个操作数,任何Num类型作为第二个操作数,然后构造任何类型。所以这意味着我可以将函数专门化为sum :: Int -> Float -> Char,但没有定义(+)

我们可以使类型更灵活,例如使用fromIntegral :: (Integral a, Num b) => a -> b

integralSum :: (Integral i, Integral j, Num c) => i -> j -> c
integralSum x y = fromIntegral x + fromIntegral y

答案 1 :(得分:7)

对于不同的答案,让我们尝试忽略除了类型签名之外的所有内容。

sum :: (Num a, Num b) => a -> b -> c

这就是说如果我给你一些类型的值,你知道它是Numa类型变量)的一个实例,我给你第二个值可以是一个不同的类型,但也是Numb类型变量),那么你知道如何给我一个任何类型的值我要求的({{1} })。

也就是说,我会给你c(3%4 :: Rational)你能不能给我(7.99 :: Double)这是我的网络服务器的配置结构?表达式val :: Config毕竟与您的类型签名相匹配。

答案 2 :(得分:5)

让我们看一下+运算符的类型。我们可以使用ghci命令在:t中执行此操作:

Prelude> :t (+)
(+) :: Num a => a -> a -> a

请注意,两个操作数和返回值都必须具有相同的类型。这就是您得到编译器错误的原因。您允许sum获取两种不同类型的操作数。因此,您可以将类型签名更改为

sum :: (Num a, Num a) => a -> a -> a

如果要添加不同类型的数字,在应用+运算符之前,您需要使用其他逻辑将参数转换为相同类型。