我正在尝试编写一个具有类型安全长度的矢量库,这意味着添加两个不同长度的矢量将无法飞行。
我目前的实施大致是:
data Natural where
Zero :: Natural
Succ :: Natural -> Natural
type One = Succ Zero
type Two = Succ One
type Three = Succ Two
type Four = Succ Three
data Vector n e where
Nil :: Vector Zero e
(:|) :: e -> Vector n e -> Vector (Succ n) e
infixr :|
我现在正在尝试实施zipWith
,因为它有助于实现dot
产品和Num
类型类等内容。
我已经走到了这一步
zipWith :: (a -> b -> c) -> Vector n a -> Vector n b -> Vector n c
zipWith f (a :| as) (b :| bs) = f a b :| zipWith f as bs
zipWith _ _ _ = Nil
但我收到错误
Couldn't match type `n' with 'Zero
`n' is a rigid type variable bound by
the type signature for
zipWith :: (a -> b -> c) -> Vector n a -> Vector n b -> Vector n c
at LinearAlgebra.hs:51:12
Expected type: Vector n c
Actual type: Vector 'Zero c
In the expression: Nil
In an equation for `zipWith': zipWith _ _ _ = Nil
我认为原因是变量n
只能采用一个值 - Succ
或Zero
?
我该如何解决这个问题?
答案 0 :(得分:7)
采取以下模式:
zipWith _ as bs = Nil
此处GHC仅从函数的签名中知道as
的类型为Vector n a
且bs
的类型为Vector n b
。此外,签名表示右侧必须具有Vector n c
类型,其中n
与左侧的其他n
- s相同。对于任意Nil
,Vector Zero x
的类型为x
。
类型不匹配,因为左侧的长度参数是未知的任意n
,而右侧的长度Zero
。参数上的模式匹配带来了必要的附加信息:
zipWith _ Nil Nil = Nil
-- "zipWith _ as Nil" also works, because now "as" is constrained to also have Zero length
如果你有GHC 7.8.x,你可以写下以下内容:
zipWith f as bs = _
和GHC将为您提供关于洞的预期类型和范围内变量类型的非常有用的消息(对于GHC的最佳知识,给定您匹配模式的构造函数)。