为什么这不起作用?
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)
我错过了什么?
因为该(+)功能有签名:
(+) :: Num a => a -> a -> aRun 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)
对于不同的答案,让我们尝试忽略除了类型签名之外的所有内容.
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毕竟,表达式与您的类型签名匹配.
我们来看看+运营商的类型.我们可以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)
如果要添加不同类型的数量,则在应用+运算符之前,需要使用其他逻辑将参数转换为相同类型.