Math 在Idris中,为什么接口参数必须是类型构造函数或数据构造函数?

Math 在Idris中,为什么接口参数必须是类型构造函数或数据构造函数?,math,types,interface,idris,type-theory,Math,Types,Interface,Idris,Type Theory,为了练习Idris,我一直在尝试将各种基本代数结构表示为接口。我最初组织事物的方式是将给定接口的参数设置为集合和对其进行的各种操作,而方法/字段则是各种公理的证明。例如,我想这样定义Group: Group (G : Type) (op : G -> G -> G) (e : G) (inv : G -> G) where assoc : {x,y,z : G} -> (x `op` y) `op z = x `op` (y `op` z) id_l : {x

为了练习Idris,我一直在尝试将各种基本代数结构表示为接口。我最初组织事物的方式是将给定接口的参数设置为集合和对其进行的各种操作,而方法/字段则是各种公理的证明。例如,我想这样定义
Group

Group (G : Type) (op : G -> G -> G) (e : G) (inv : G -> G) where
  assoc : {x,y,z : G} -> (x `op` y) `op z = x `op` (y `op` z)
  id_l  : {x : G} -> x `op` e = x
  id_r  : {x : G} -> x `op` e = x
  inv_l : {x : G} -> x `op` (inv x) = e
  inv_r : {x : G} -> (inv x) `op` x = e
我之所以这样做,而不是仅仅使用
op
e
inv
方法,是因为用不同的方式谈论同一组会更容易。比如,从数学上讲,把一个集合说成一个群体是没有意义的;只有将指定操作作为组的集合进行讨论才有意义。通过定义不同的操作,同一组可以对应于两个完全不同的组。另一方面,各种界面定律的证明并不影响群体。虽然法律的居民(证据)可能不同,但它不会导致不同的群体。因此,声明多个实现是没有用的

更根本的是,这种方法似乎更能代表数学概念。将集合称为一个组是一个类别错误,因此我的数学家对于将组操作作为一个接口方法来断言那么多内容并不感到兴奋


然而,这个计划是不可能的。当我尝试时,它实际上会进行类型检查,但当我尝试定义一个实例时,它不会:idris抱怨说,例如:

(+) cannot be a parameter of Algebra.Group
(Implementation arguments must be type or data constructors)
我的问题是:为什么会有这种限制?我想这是有充分理由的,但就我个人而言,我看不出来。比如,我认为Idris折叠了值/类型/种类层次结构,所以类型和值之间没有真正的区别,那么为什么实现要特别处理类型呢?为什么要对数据构造函数进行特殊处理?在我看来,这似乎是武断的


现在,我可以使用命名的实现来实现同样的事情,我想我现在就要这么做了。我想我已经习惯了Haskell,在这里,对于给定的数据类型,一个typeclass只能有一个实例。但这仍然让人觉得很武断。。。。特别是,我希望能够将半环定义为元组
(R,+,*,0,1)
,其中
(R,+,0)
是一个幺半群,
(R,*,1)
是一个幺半群(附加了分配律)。但我认为如果没有上述方案,即使使用命名实现,我也无法轻松做到这一点。我只能说R是否是幺半群——但对于半环,它需要以两种不同的方式成为幺半群!我肯定有一些样板类型的同义词或其他东西的变通方法(我最后可能会这样做),但我真的不明白为什么有必要这样做



我也在尝试类似的事情:我回家后会给出一些细节,限制在中讨论。这似乎是一件务实的事情。该方法将运算符和定律放在同一界面中。就个人而言,我不相信接口是实现这一点的最佳工具(参见diamond继承)。我喜欢运算符的接口,因为它们提供了干净的表示法,可以是加法,也可以是乘法,具体取决于当前的情况。目前,我更喜欢捕获普通依赖类型中的规范。
$ idris --version
1.2.0