Haskell签名:基础知识

Big*_*ter 5 haskell

为什么这不起作用?

sum :: (Num a, Num b) => a -> b -> c
sum a b = a + b
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

我错过了什么?

Wil*_*sem 8

因为该(+)功能有签名:

(+) :: Num a => a -> a -> a
Run Code Online (Sandbox Code Playgroud)

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

您的签名意味着程序员可以选择任何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
Run Code Online (Sandbox Code Playgroud)


Tho*_*son 7

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

sum :: (Num a, Num b) => a -> b -> c
Run Code Online (Sandbox Code Playgroud)

这说明如果我给你一些类型的值,你知道它是Num(a类型变量)的一个实例,我给你第二个值,它可以是一个不同的类型,但也是一个Num(b类型变量),那么你知道如何给我一个我要求的任何类型的值(c).

也就是说,我打算给你(3%4 :: Rational),(7.99 :: Double) 请你给我val :: Config一个我的网络服务器的配置结构?sum (3%4) 7.99 :: Config毕竟,表达式与您的类型签名匹配.


Cod*_*ice 5

我们来看看+运营商的类型.我们可以ghci使用以下:t命令执行此操作:

Prelude> :t (+)
(+) :: Num a => a -> a -> a
Run Code Online (Sandbox Code Playgroud)

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

sum :: (Num a, Num a) => a -> a -> a
Run Code Online (Sandbox Code Playgroud)

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