无法匹配Haskell类型

无法匹配Haskell类型,haskell,Haskell,我知道在这个话题上有很多问题,但我觉得我正在使用的库中有一些特定的东西给了我错误 module Test where import Clash.Prelude init' :: Vec (n + 1) a -> Vec n a init' (_ :> Nil) = Nil init' (x :> (xs:>ys)) = x :> (init' (xs:>ys)) 我得到的错误是 Test.hs:28:14: error: • Couldn't m

我知道在这个话题上有很多问题,但我觉得我正在使用的库中有一些特定的东西给了我错误

module Test where

import Clash.Prelude

init' :: Vec (n + 1) a -> Vec n a
init' (_ :> Nil) = Nil
init' (x :> (xs:>ys)) = x :> (init' (xs:>ys))
我得到的错误是

Test.hs:28:14: error:
    • Couldn't match type ‘n’ with ‘n0 + 1’
      ‘n’ is a rigid type variable bound by
        the type signature for:
          init' :: forall (n :: Nat) a. Vec (n + 1) a -> Vec n a
        at Test.hs:26:1-33
      Expected type: Vec n a
        Actual type: Vec (n0 + 1) a
    • In the pattern: xs :> ys
      In the pattern: x :> (xs :> ys)
      In an equation for ‘init'’:
          init' (x :> (xs :> ys)) = x :> (init' (xs :> ys))
    • Relevant bindings include
        init' :: Vec (n + 1) a -> Vec n a (bound at Test.hs:27:1)
   |
28 | init' (x :> (xs:>ys)) = x :> (init' (xs:>ys))
   | 
Clash.Prelude库中的定义如下

data Vec :: Nat -> * -> * where
  Nil  :: Vec 0 a
  Cons :: a -> Vec n a -> Vec (n + 1) a

pattern (:>) :: a -> Vec n a -> Vec (n + 1) a
pattern (:>) x xs <- ((\ys -> (head ys,tail ys)) -> (x,xs))
  where
    (:>) x xs = Cons x xs
data-Vec::Nat->*->*其中
零::向量0 a
缺点:a->Vec n a->Vec(n+1)a
模式(:>)::a->Vec n a->Vec(n+1)a
模式(:>)x x x(头部y,尾部y))->(x,x))
哪里
(:>)x xs=Cons x xs

这是碰撞库中的错误/限制。你会发现你甚至不能定义一些简单的东西,比如:

safeHead :: Vec n a -> Maybe a
safeHead Nil = Nothing
safeHead (x :> _) = Just x
问题在于
(:>)
模式的定义:

pattern (:>) :: a -> Vec n a -> Vec (n + 1) a
pattern (:>) x xs <- ((\ys -> (head ys,tail ys)) -> (x,xs))
  where
    (:>) x xs = Cons x xs
推断的类型签名应该是:

pattern (:>) :: () => (n ~ n1 + 1) => a -> Vec n1 a -> Vec n a
(这也可以明确给出),并且您的代码可以很好地工作(如果您能够直接使用
Cons
代替
(:>

这种签名的不寻常形式,有两组约束,是针对模式同义词的。第一组约束给出了一组“必需的”约束,这些约束条件是为了满足使用模式正确的代码而考虑的,第二组给出了“提供”的集合。约束,即通过在运行时实际匹配模式而在案例分支中纳入范围的约束。您可以在GHC文档中了解更多有关这方面的信息

不幸的是,库中使用的显式签名:

pattern (:>) :: a -> Vec n a -> Vec (n + 1) a
相当于:

pattern (:>) :: (n ~ n1 + 1) => () => Vec n1 a -> Vec n a
其中
n
n1
上的约束出现在“必需”约束集中,而不是“提供”约束集中。这是一个大问题

init'
定义的这一部分中:

init' (x :> (xs:>ys)) = x :> (init' (xs:>ys))
第一个
:>
要求由整个表达式
x:>(xs:>ys)
匹配的参数对于某些
n
Vec(n+1)a
。幸运的是,这是因为
init'
的类型签名。不幸的是,第二个
:>
要求参数(已知类型为
Vec n a
)对于某些
m
,为
Vec(m+1)a
,以进行类型检查。没有此类约束可用!这将是第二个
:>
的匹配(与前一行中的
Nil
的匹配相反)这将提供这样的约束

最终,我们陷入了一种约束循环,为了为一些
m
提供
n~m+1
,我们需要为一些
m
提供
n~m+1


那么,你能做什么呢?很难说。根据
Clash
更改日志,这个奇怪的模式定义是故意添加的,这样“Clash编译器现在可以合成
上的模式匹配:>
”。我不知道这意味着什么,但冲突维护者可能知道。我会给他或她发送一封电子邮件,指出
(:>)的模式定义
阻止您执行简单的操作,如定义
safeHead
init'
,并查看他或她是否可以重写模式,以便既允许正确的模式匹配,又保持此“可合成”业务运作。

什么是
:>
?您是否尝试过直接使用
Cons
指定模式?@max630,是的,我使用了Cons,我更新了:>的定义,以及您使用
Cons
是什么意思?它不是由库导出的。您是如何使用它的?@K.A.Buhr,您把我带到了那里。我使用了它,并得到了错误t它不是由图书馆导出的!我在那里的糟糕、粗心的评论。哇!你对Haskell的了解给我留下了深刻的印象,并且假设你阅读了Clash图书馆的文档,你成功地获得了这么多信息!非常感谢你抽出时间回答这个问题。这是一个令人惊讶的答案!请参阅(
:>
)上的讨论vs
Cons
太多了:@Martijn,是的!我也在谷歌群上讨论过同样的问题。谢谢!
init' (x :> (xs:>ys)) = x :> (init' (xs:>ys))