Haskell错误中的Semigroup / Monoid / Group类型层次结构

时间:2011-07-13 08:09:27

标签: haskell typeclass algebra

我正在尝试创建代数类型类的“层次结构”,如下所示:

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可以在这种情况下工作。

2 个答案:

答案 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-}