函数最终生成值的类型以( 开头,但列表的类型以[ 开头。他们不能匹配,所以你的方法不可能是正确的。但我们可以修复它。
您尝试将值与变量的元组进行模式匹配是正确的,但实际上模式在等号的左边,值在等号的右边。而且它必须在let:
add1 :: (Int,Int) -> (Int,Int) -> [(Int,Int)] -- NB: added brackets!
add1 a b = [(x, y) | let (x1, y1) = a ; (x2, y2) = b ;
x = x1 + x2 ; y = y1 + y2 ]
实际上我们不需要let 在列表理解中,
add2 :: (Int,Int) -> (Int,Int) -> [(Int,Int)]
add2 a b = let { (x1, y1) = a ; (x2, y2) = b ;
x = x1 + x2 ; y = y1 + y2 } in
[(x, y)]
现在我们可以去掉那些括号,得到你想要的值和类型。
还有另一种有点棘手的方法可以让您的原始代码在不更改任何内容in的情况下工作(除了修复add 的错误大写并使其成为正确的let 语法) .
我们只需添加一个词并启用一个扩展,它就可以工作:
{-# LANGUAGE MonadComprehensions #-}
import Data.Function.Identity
add :: (Int,Int) -> (Int,Int) -> (Int,Int)
add a b = magicWord
[(x, y) | let { (x1, y1) = a ; (x2, y2) = b ;
x = x1 + x2 ; y = y1 + y2 } ]
神奇的词是
magicWord = runIdentity
使用该扩展,推断的定义类型是
add :: (Num t1, Num t, Monad m)
=> (t, t1) -> (t, t1) -> m (t, t1)
自从
runIdentity :: Identity a -> a
使用它会强制使用m ~ Identity,它就可以工作:派生类型是
(Num t1, Num t, Monad m)
=> (t, t1) -> (t, t1) -> m (t, t1)
Identity a -> a
--------------------------------------------
m ~ Identity , Monad Identity
(t,t1) ~ a
--------------------------------------------
(Num t1, Num t)
=> (t, t1) -> (t, t1) -> (t, t1)
与您给定的类型签名匹配
(Int, Int) -> (Int, Int) -> (Int, Int)
因为Int在Num中,
Identity 确实是一个 monad,什么都不做,
newtype Identity a = Identity {runIdentity :: a}
fmap f (Identity a) = Identity (f a)
join (Identity (Identity a)) = Identity a
除了用它的标签标记值,它甚至会立即消失,因为类型Identity a被定义为newtype,而不是data。