5

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

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 aMonoid a将能够看到 function (.*)。此外,foldr1Prelude 中的类型没有限制,所以我认为这foldr1在这种情况下会起作用。

4

2 回答 2

6

Haskell 不允许您根据术语声明(或强制执行)方程式(就像您想要做的那样)。这是出于一个非常实际的原因:在像 Haskell 这样丰富的编程语言中证明任意项之间的相等性是不可判定的。检查人工构建的证明通常是可以确定的,但在编程时必须编写和跟踪这些证明也有些烦人。

尽管如此,如果这是您想要定期做的事情,那么有些语言可以做到这一点;要搜索的术语是“依赖类型”。例如,Coq 和 Agda 可能是目前最流行的两种依赖类型语言,每一种语言都使得编写一种只由良好、守法的半群(或幺半群)存在的类型变得非常简单。

于 2011-07-14T00:50:05.670 回答
4

我不确定你想做什么。

如果您尝试为 in 提供默认值,并为foldr1in提供默认值,那么您不能。Semigroup(.*)Monoid

  • foldr1在 Prelude 中被定义为非类型类函数,所以你不能给它一个本地定义Semigroup
  • (.*)Semigroup班级的一部分。你可以在Semigroup实例中给出它的值,你可以在类中给它一个默认值Semigroup,但你不能在Monoid类(或Monoid实例)中给出它的值

如果您尝试为 in 提供默认值,并为(.*)in提供默认值,那么您使用的语法错误。SemigroupidentityMonoid

而是尝试类似的东西

class Semigroup a where
    (.*) :: a -> a -> a
    (.*) = {-something-}

或者

class Semigroup a where
    (.*) :: a -> a -> a
    x .* y = {-something-}
于 2011-07-13T08:29:30.737 回答