为类型安全的向量实现zipWith

时间:2014-05-29 10:09:55

标签: haskell types linear-algebra

我正在尝试编写一个具有类型安全长度的矢量库,这意味着添加两个不同长度的矢量将无法飞行。

我目前的实施大致是:

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只能采用一个值 - SuccZero

我该如何解决这个问题?

1 个答案:

答案 0 :(得分:7)

采取以下模式:

zipWith _ as bs = Nil

此处GHC仅从函数的签名中知道as的类型为Vector n abs的类型为Vector n b。此外,签名表示右侧必须具有Vector n c类型,其中n与左侧的其他n - s相同。对于任意NilVector 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的最佳知识,给定您匹配模式的构造函数)。