开发者

Semigroup/Monoid/Group type class hierarchy in Haskell errors

开发者 https://www.devze.com 2023-03-19 17:45 出处:网络
I\'m trying to create a \"hierarchy\" of algebraic type classes, as follows: class Semigroup a where (.*)开发者_如何学Go :: a -> a -> a

I'm trying to create a "hierarchy" of algebraic type classes, as follows:

class Semigroup a where
  (.*)开发者_如何学Go :: 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

Thus, groups are monoids and monoids are semigroups. However, I get errors that the classes can't see the functions of their parent class.

These errors bug me because I assumed that by writing (for example) class (Semigroup a) => Monoid a the class Monoid a would be able to see the function (.*). And furthermore, the type of foldr1 in the Prelude has no constraints, so I assumed that foldr1 would work in this context.


Haskell does not allow you to declare (or enforce) equations on terms (like it seems like you want to do). This is for a very practical reason: proving equalities between arbitrary terms in a programming language as rich as Haskell is undecidable. Checking a human-constructed proof is often decidable, but it is also somewhat annoying to have to write and track these proofs while programming.

Still, if this is the kind of thing you want to do on a regular basis, there are languages that make this possible; the term to search for is "dependent types". For example, Coq and Agda are perhaps the two most popular dependently typed languages at the moment, and each would make it dead-simple to write a type inhabited only by good, law-abiding semigroups (or monoids).


I'm not sure what you're trying to do.

If you're trying to provide a default value for foldr1 in Semigroup, and a default value for (.*) in Monoid, then you can't.

  • foldr1 is defined in the Prelude as a non-typeclass function, so you can't give it a local definition in Semigroup
  • (.*) is part of the Semigroup class. You can give its values in Semigroup instances, and you can give a default value for it in the Semigroup class, but you can't give its value in the Monoid class (or Monoid instances)

If you're trying to to provide a default value for (.*) in Semigroup, and a default value for identity in Monoid, then you're using the wrong syntax.

Instead try something like

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

or

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

精彩评论

暂无评论...
验证码 换一张
取 消