在Idris中使用依赖对进行练习时,我在编译的程序和REPL之间遇到了意外的行为差异。以下是我正在测试的数据类型:
(a : Type ** b : Type ** Arrow a b)
应该表示类型a
和类型b
之间的某种关系。给定上述情况的一个例子,我想提取该类型的“证明”一词。我可以使用DPair.snd $ DPair.snd <some-instance>
从REPL进行此操作,一切正常。但是,如果我尝试创建一个函数:
unwrap : (a ** b ** Arrow a b) -> Arrow a b
unwrap x = DPair.snd $ DPair.snd x
该程序将编译,但是当我尝试调用它时将失败。返回的错误消息是
(input): No such variable b
有人遇到过这种情况或知道解决方案吗?
答案 0 :(得分:0)
您想实现的目标是不可能的。如果查看unwrap : (a1 : Type ** b1 : Type ** Arrow a b) -> Arrow a b
的类型,则会发现它使用的数据类型与(a : Type ** b : Type ** Arrow a b)
不同。这是因为参数a
,b
是预先量化的-设置了结果类型(这也是REPL情况的区别;您不必绑定到参数)。因此,:set showimplicit
是
Main.unwrap : {b : Type} -> {a : Type} ->
(a1 : Type ** b1 : Type ** Main.Arrow a b) ->
Main.Arrow a b
这就是依赖对的问题,您不能轻易限制它们。看看Vect.filter : (elem -> Bool) -> Vect len elem -> (p : Nat ** Vect p elem)
-如果我们有一个像unwrap : (p : Nat ** Vect p elem) -> Vect p elem
这样的函数,那么我们就不需要依赖对了。
相反,调用unwrap
的函数将需要检查p
,然后相应地处理Vect
。遗憾的是,我们无法轻松检查类型(至少如果要对所有类型进行概括)。所以最好的选择是:不要在这里使用依赖类型。
答案 1 :(得分:0)
我意识到我要迟到一年半了,但是...这绝对有可能!您只需要记住类型a ** P
只是DPair a (\x => P a)
的语法糖;在后一种形式中,没有什么特别的事情发生,因此您可以像期望的那样使用a
和b
。我们还可以通过在标准库中键入DPair.snd
来获得洞察力:
Idris> :t DPair.snd
snd : (x : DPair a P) -> P (fst x)
因此,要从我们的货币对中提取a
值,我们只需在该货币对上调用fst
。多么直观! (fst
本身只是类型DPair a P -> a
)。要获取b
值(这是我们对第二部分的第一个值),我们在最外面的对上调用fst . snd
。因此,您的函数应如下所示:
unwrap : (x : DPair a (DPair b . Arrow)) -> Arrow (fst x) (snd $ fst x)
unwrap x = snd (snd x)
(或等价的:)
unwrap : (x : DPair a (\theA => DPair b (\theB => Arrow theA theB))) -> ...
无论出于何种原因,unwrap = DPair.snd . DPair.snd
都不起作用...但这并不是一个太大的问题。