无法匹配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图书馆的文档,你成功地获得了这么多信息!非常感谢你抽出时间回答这个问题。这是一个令人惊讶的答案!请参阅(:>
)上的讨论vsCons
太多了:@Martijn,是的!我也在谷歌群上讨论过同样的问题。谢谢!
init' (x :> (xs:>ys)) = x :> (init' (xs:>ys))