我正在尝试创建代数类型类的“层次结构”,如下所示:
class Semigroup a where
(.*) :: a -> a -> a
foldr1 (.*) = foldl1 (.*) -- GHCi error: "`foldr1' is not a (visible) method of class `Semigroup'"
class (Semigroup a) => Monoid a where
identity :: a
(.*) identity = id :: a -> a -- GHCi error: "`.*' is not a (visible) method of class `Monoid'"
class (Monoid a) => Group a where
inverse :: a -> a
因此,群是幺半群,幺半群是半群。但是,我得到的错误是类无法看到其父类的功能。
这些错误让我感到不安,因为我认为通过编写(例如)class (Semigroup a) => Monoid a
,类Monoid a
将能够看到函数(.*)
。此外,Prelude中foldr1
的类型没有约束,所以我假设foldr1
可以在这种情况下工作。
答案 0 :(得分:5)
Haskell不允许您在术语上声明(或强制执行)等式(就像您想要的那样)。这是一个非常实际的原因:证明编程语言中任意项之间的平等性与Haskell一样丰富是不可判定的。检查人工构造的证明通常是可以判断的,但是在编程时必须编写和跟踪这些证据也有点烦人。
但是,如果这是你想要定期做的事情, 语言可以使这成为可能;搜索的术语是“依赖类型”。例如,Coq和Agda可能是目前最受欢迎的两种依赖类型的语言,每种语言都会使编写一种仅由良好的守法半群(或幺半群)居住的类型变得简单。
答案 1 :(得分:4)
我不确定你要做什么。
如果您尝试在foldr1
中为Semigroup
提供默认值,在(.*)
中为Monoid
提供默认值,则不能。< / p>
foldr1
在Prelude中定义为非类型类函数,因此您无法在Semigroup
(.*)
是Semigroup
课程的一部分。您可以在Semigroup
个实例中提供其值,并且可以在Semigroup
类中为其指定默认值,但不能在Monoid
类中提供其值(或{ {1}}个实例)如果您尝试在Monoid
中为(.*)
提供默认值,在Semigroup
中为identity
提供默认值,那么您正在使用错误的语法。
而是尝试像
这样的东西Monoid
或
class Semigroup a where
(.*) :: a -> a -> a
(.*) = {-something-}