Semigroup/Monoid/Group type class hierarchy in Haskell errors
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 inSemigroup
(.*)
is part of theSemigroup
class. You can give its values inSemigroup
instances, and you can give a default value for it in theSemigroup
class, but you can't give its value in theMonoid
class (orMonoid
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-}
精彩评论