我只阅读了standard tutorial并且稍微摸了一下,所以我可能会遗漏一些简单的东西。
如果Idris无法做到这一点,请解释原因。此外,如果可以用其他语言完成,请提供代码示例,并解释该语言类型系统的不同之处。
这是我的方法。问题首先出现在第三部分。
v : List Nat
v = []
这在REPL中编译并显示为[] : List Nat
。优异。
emptyList : (t : Type) -> List t
emptyList t = []
v' : List Nat
v' = emptyList Nat
不出所料,这可行,v' == v
。
Ord
类emptyListOfOrds : Ord t => (t : Type) -> List t
emptyListOfOrds t = []
v'' : List Nat
v'' = emptyListOfOrds Nat -- !!! typecheck failure
最后一行因此错误而失败:
When elaborating right hand side of v'':
Can't resolve type class Ord t
Nat
是Ord
的一个实例,那么问题是什么?我尝试将Nat
中的v''
替换为Bool
(不是Ord
的实例),但错误没有变化。
使Ord t
显式参数满足类型检查器吗?显然不是,但即使它确实要求呼叫者传递冗余信息也不是理想的。
emptyListOfOrds' : Ord t -> (t : Type) -> List t
emptyListOfOrds' a b = []
v''' : List Nat
v''' = emptyListOfOrds (Ord Nat) Nat -- !!! typecheck failure
这次错误更详细:
When elaborating right hand side of v''':
When elaborating an application of function stackoverflow.emptyListOfOrds':
Can't unify
Type
with
Ord t
Specifically:
Can't unify
Type
with
Ord t
我可能错过了一些关于如何根据类型声明检查值的关键见解。
答案 0 :(得分:8)
正如其他答案所解释的那样,这是关于变量t
的约束方式和位置。也就是说,当你写:
emptyListOfOrds : Ord t => (t : Type) -> List t
阐述者会看到' t'在Ord t
中使用它时未绑定,因此隐式绑定它:
emptyListOfOrds : {t : Type} -> Ord t => (t : Type) -> List t
所以你真正想说的是有点像:
emptyListOfOrds : (t : Type) -> Ord t => List t
哪个会在类型类约束之前绑定t,因此当Ord t
出现时它就在范围内。不幸的是,这种语法不受支持。我认为没有理由不支持这种语法,但目前还没有。
你仍然可以实现你想要的东西,但它很难看,我很害怕:
由于类是第一类,因此可以将它们作为普通参数提供:
emptyListOfOrds : (t : type) -> Ord t -> List t
然后,当您致电%instance
时,您可以使用特殊语法emptyListOfOrds
搜索默认实例:
v'' = emptyListOfOrds Nat %instance
当然,您并不是真的想在每个呼叫站点都这样做,因此您可以使用默认的隐式参数来为您调用搜索过程:
emptyListOfOrds : (t : Type) -> {default %instance x : Ord t} -> List t
v'' = emptyListOfOrds Nat
如果没有明确给出其他值,default val x : T
语法将使用默认值x
填充隐式参数val
。将%instance
作为默认值然后与类约束发生的情况完全相同,实际上我们可能会改变Foo x =>
语法的实现来完成这个......我认为这是我唯一的原因当我最初实现类型类时,default
个参数还没有存在。
答案 1 :(得分:2)
你可以写
emptyListOfOrds : Ord t => List t
emptyListOfOrds = []
v'' : List Nat
v'' = emptyListOfOrds
或许如果你愿意
v'' = emptyListOfOrds {t = Nat}
如果你按照你写的方式询问emptyListOfOrds的类型,你得到
Ord t => (t2 : Type) -> List t2
在repl中:set showimplicits
上图示,然后再次询问
{t : Type} -> Prelude.Classes.Ord t => (t2 : Type) -> Prelude.List.List t2
似乎指定Ord t
约束引入了隐式参数t
,然后为您的显式参数t
分配了新名称。您始终可以为该隐式参数显式提供值,例如emptyListOfOrds {t = Nat} Nat
。至于这是"权利"出于某种原因的行为或限制,也许你可以在github上打开这个问题?也许与显式类型参数和类型类约束存在一些冲突?通常情况下,类型类是在你隐式解决的时候...虽然我想我记得有语法来获得对类型类实例的显式引用。
答案 2 :(得分:0)
不是答案,只是一些想法。
这里的问题是(t : Type)
引入了扩展到右边的新范围,但Ord t
超出了此范围:
*> :t emptyListOfOrds
emptyListOfOrds : Ord t => (t2 : Type) -> List t2
您可以在引入类型变量后添加类约束:
emptyListOfOrds : (t : Type) -> Ord t -> List t
emptyListOfOrds t o = []
但现在你需要明确指定类实例:
instance [natord] Ord Nat where
compare x y = compare x y
v'' : List Nat
v'' = emptyListOfOrds Nat @{natord}
可能以某种方式使Ord t
参数隐含。