将列表转换为类型安全的向量

sda*_*das 4 haskell

我正在尝试编写该函数

fromList :: [e] -> Vector n e
fromList [] = Nil
fromList (x:xs) = x :| fromList xs
Run Code Online (Sandbox Code Playgroud)

使用这个向量的定义

data Natural where
    Zero :: Natural
    Succ :: Natural -> Natural

data Vector n e where
  Nil  :: Vector Zero e
  (:|) :: e -> Vector n e -> Vector (Succ n) e

infixr :|
Run Code Online (Sandbox Code Playgroud)

但是,Haskell给出了错误

    Couldn't match type 'Zero with 'Succ n0
    Expected type: Vector n e
      Actual type: Vector ('Succ n0) e
    In the expression: x :| fromList xs
    In an equation for `fromList': fromList (x : xs) = x :| fromList xs
Failed, modules loaded: none.
Run Code Online (Sandbox Code Playgroud)

我相信错误是因为类型签名而引发的(:|).

有没有办法解决这个错误?

lef*_*out 5

错误是您的类型签名是普遍量化n,即它表示"对于任何n,我们可以n从列表中构建长度向量".与此不同,函数定义表明向量始终具有给定列表的长度.

基本上,您需要存在量化来定义此函数("取决于列表长度,将有一个n这样n的结果向量的长度").仅在昨天讨论过,您不能在签名中使用存在量化的类型变量.你可以拥有的是存在主义类型 - 最好再写为GADT,

data DynVector e where
  DynVector :: Vector n e -> DynVector e
Run Code Online (Sandbox Code Playgroud)

然后你可以定义

fromList' :: [e] -> DynVector e
fromList' [] = DynVector Nil
fromList' (x:xs) = case fromList xs of
   DynVector vs -> DynVector $ x :| vs
Run Code Online (Sandbox Code Playgroud)

  • 嗯,是的,有点。但这是不可避免的,在您从没有任何类型保证的长度保证的类型开始之后。 (2认同)