Eq definition for alternative version numbering approach - haskell

I am trying to define Eq operator for alternative version numbering approach.
type VersionCompound = Maybe Int -- x, 0, 1, 2, ...
type VersionNumber = [VersionCompound] -- x.x, x.0, x.1, x.2, ... , 1.0, 1.1, 1.2, ... 1.x.x, 2.x.x, 3.x.x, ...
instance Eq VersionNumber where
[] == [] = True
(x:[]) == (y:[]) = x == y
(Nothing:xs) == ys = (xs == ys)
xs == (Nothing:ys) = (xs == ys)
It is expected that it returns True for following cases: x.x.x == x, 1.x.x == x.1.x.x, x.1 == 1, etc. But instead it returns an error:
VersionNumber.hs:58:34:
Overlapping instances for Eq [VersionCompound]
arising from a use of ‘==’
Matching instances:
instance Eq a => Eq [a] -- Defined in ‘GHC.Classes’
instance Eq VersionNumber -- Defined at VersionNumber.hs:55:10
In the expression: (xs == ys)
In an equation for ‘==’: (Nothing : xs) == ys = (xs == ys)
In the instance declaration for ‘Eq VersionNumber’
Any ideas how to fix it?
EDIT: My approach to this problem via pattern matching on lists turned out to be incomplete. I wanted to disregard any arbitrary list of x's (or Nothings) on the left hand side of the given version. So, for example, x.x.x.x.x would be equal to x.x.x and to x. Similarly, x.x.x.1 would be equal to x.x.1 and to 1. If there's an x in the middle, it won't be thrown away. So, for this case, x.x.1.x.0 would be equal to x.1.x.0 and 1.x.0. Yet another example: x.1.x.x.0.x is equal to 1.x.x.0.x and x.1.x.0.x is equal to 1.x.0.x (You just remove x's on the left side).
What I was struggling with after fixing an error Overlapping instances for Eq [VersionCompound] is how to get x.x.x == x -> True with pattern matching. But, as #WillemVanOnsem brilliantly noted, it should be achieved not via pattern matching, but with function composition.
PS. I personally encourage you to upvote the answer by #WillemVanOnsem because his solution is really elegant, required some effort to come up with and represents the essence of Haskell power.

You use type aliases. This means that you have not defined a separate type VersionNumber or VersionCompound; you simply have constructed an alias. Behind the curtains, Haskell sees VersionNumber as simply [Maybe Int].
Now if we look at Haskell's library, we see that:
instance Eq Int where
-- ...
instance Eq a => Eq (Maybe a) where
-- ...
instance Eq a => Eq [a] where
-- ...
So that means that Eq Int is defined, that Eq (Maybe Int) is defined as well, and thus that Eq [Maybe Int] is defined by the Haskell library as well. So you actually have already constructed an Eq VersionNumber without writing one. Now you try to write an additional one and, of course, the compiler gets confused with which one to pick.
There are ways to resolve overlapping instances, but this will probably only generate more trouble.
Thus, you better construct a data type with a single constructor. For example:
type VersionCompound = Maybe Int
data VersionNumber = VersionNumber [VersionCompound]
Now, since there is only one constructor, you better use a newtype:
type VersionCompound = Maybe Int
newtype VersionNumber = VersionNumber [VersionCompound]
and now we can define our special instance like:
instance Eq VersionNumber where
(VersionNumber a) == (VersionNumber b) = a =*= b
where [] =*= [] = True
(x:[]) =*= (y:[]) = x == y
(Nothing:xs) =*= ys = (xs =*= ys)
xs =*= (Nothing:ys) = (xs =*= ys)
So we thus unwrap the constructors and then use another locally defined function =*= that works like you defined it in your question.
Mind however that you forgot a few patterns in your program, like for instance Just x : xs on both the left and the right side. So, you better fix these first. If I run your code through a compiler, I get the following warnings:
Pattern match(es) are non-exhaustive
In an equation for ‘=*=’:
Patterns not matched:
[] (Just _:_)
[Just _] []
[Just _] (Just _:_:_)
(Just _:_:_) []
How you want to handle these cases is of course up to you. #DanielWagner suggests to use:
import Data.Function(on)
import Data.Maybe(catMaybes)
instance Eq VersionNumber where
(VersionNumber a) == (VersionNumber b) = on (==) catMaybes a b
This will filter out the Nothing values of both VersionNumbers and then check whether the values in the Just generate the same list. So 3.x.2.x.x.1 will be equal to 3.2.1 and x.x.x.x.x.3.2.1.
EDIT: based on your specification in comment, you are probably looking for:
import Data.Function(on)
instance Eq VersionNumber where
(VersionNumber a) == (VersionNumber b) = on (==) (dropWhile (Nothing ==)) a b

Related

Design options for constructor constraints: GADT compare PatternSynonym Required

(This is a follow-up to this answer, trying to get the q more precise.)
Use Case Constructors to build/access a Set datatype. Being a set, the invariant is 'no duplicates'. To implement that I need an Eq constraint on the element type. (More realistically, the set might be implemented as a BST or hash-index, which'll need a more restrictive constraint; using Eq here to keep it simple.)
I want to disallow building even an empty set with an unacceptable type.
" it's now considered bad practice to require a constraint for an operation (data type construction or destruction) that does not need the constraint. Instead, the constraints should be moved closer to the "usage site".", to quote that answer.
OK so there's no need to get the constraint 'built into' the data structure. And operations that access/deconstruct (like showing or counting elements) won't necessarily need Eq.
Then consider two (or rather five) possible designs:
(I'm aware some of the constraints could be achieved via deriving, esp Foldable to get elem. But I'll hand-code here, so I can see what minimal constraints GHC wants.)
Option 1: No constraints on datatype
data NoCSet a where -- no constraints on the datatype
NilSet_ :: NoCSet a
ConsSet_ :: a -> NoCSet a -> NoCSet a
Option 1a. use PatternSynonym as 'smart constructor'
pattern NilSet :: (Eq a) => () => NoCSet a
pattern NilSet = NilSet_
pattern ConsSet x xs <- ConsSet_ x xs where
ConsSet x xs | not (elemS x xs) = ConsSet_ x xs
elemS x NilSet_ = False
elemS x (ConsSet_ y ys) | x == y = True -- infers (Eq a) for elemS
| otherwise = elemS x ys
GHC infers the constraint elemS :: Eq t => t -> NoCSet t -> Bool. But it doesn't infer a constraint for ConsSet that uses it. Rather, it rejects that definition:
* No instance for (Eq a) arising from a use of `elemS'
Possible fix:
add (Eq a) to the "required" context of
the signature for pattern synonym `ConsSet'
Ok I'll do that, with an explicitly empty 'Provided' constraint:
pattern ConsSet :: (Eq a) => () => ConsType a -- Req => Prov'd => type; Prov'd is empty, so omittable
Consequently inferred type (\(ConsSet x xs) -> x) :: Eq a => NoCSet a -> a, so the constraint 'escapes' from the destructor (also from elemS), whether or not I need it at the "usage site".
Option 1b. Pattern synonym wrapping a GADT constructor as 'smart constructor'
data CSet a where CSet :: Eq a => NoCSet a -> CSet a -- from comments to the earlier q
pattern NilSetC = CSet NilSet_ -- inferred Eq a provided
pattern ConsSetC x xs <- CSet (ConsSet_ x xs) where -- also inferred Eq a provided
ConsSetC x xs | not (elemS x xs) = CSet (ConsSet_ x xs)
GHC doesn't complain about the lack of signature, does infer pattern ConsSetC :: () => Eq a => a -> NoCSet a -> CSet a a Provided constraint, but empty Required.
Inferred (\(ConsSetC x xs) -> x) :: CSet p -> p, so the constraint doesn't escape from a "usage site".
But there's a bug: to Cons an element, I need to unwrap the NoCSet inside the CSet in the tail then re-wrap a CSet. And trying to do that with the ConsSetC pattern alone is ill typed. Instead:
insertCSet x (CSet xs) = ConsSetC x xs -- ConsSetC on rhs, to check for duplicates
As 'smart constructors' go, that's dumb. What am I doing wrong?
Inferred insertCSet :: a -> CSet a -> CSet a, so again the constraint doesn't escape.
Option 1c. Pattern synonym wrapping a GADT constructor as 'smarter constructor'
Same setup as option 1b, except this monster as ViewPattern for the Cons pattern
pattern ConsSetC2 x xs <- ((\(CSet (ConsSet_ x' xs')) -> (x', CSet xs')) -> (x, xs)) where
ConsSetC2 x (CSet xs) | not (elemS x xs) = CSet (ConsSet_ x xs)
GHC doesn't complain about the lack of signature, does infer pattern ConsSetC2 :: a -> CSet a -> CSet a with no constraint at all. I'm nervous. But it does correctly reject attempts to build a set with duplicates.
Inferred (\(ConsSetC2 x xs) -> x) :: CSet a -> a, so the constraint that isn't there doesn't escape from a "usage site".
Edit: ah, I can get a somewhat less monstrous ViewPattern expression to work
pattern ConsSetC3 x xs <- (CSet (ConsSet_ x (CSet -> xs))) where
ConsSetC3 x (CSet xs) | not (elemS x xs) = CSet (ConsSet_ x xs)
Curiously inferred pattern ConsSetC3 :: () => Eq a => a -> CSet a -> CSet a -- so the Provided constraint is visible, unlike with ConsSetC2, even though they're morally equivalent. It does reject attempts to build a set with duplicates.
Inferred (\(ConsSetC3 x xs) -> x) :: CSet p -> p, so that constraint that is there doesn't excape from "usage sites".
Option 2: GADT constraints on datatype
data GADTSet a where
GADTNilSet :: Eq a => GADTSet a
GADTConsSet :: Eq a => a -> GADTSet a -> GADTSet a
elemG x GADTNilSet = False
elemG x (GADTConsSet y ys) | x == y = True -- no (Eq a) 'escapes'
| otherwise = elemG x ys
GHC infers no visible constraint elemG :: a -> GADTSet a -> Bool; (\(GADTConsSet x xs) -> x) :: GADTSet p -> p.
Option 2a. use PatternSynonym as 'smart constructor' for the GADT
pattern ConsSetG x xs <- GADTConsSet x xs where
ConsSetG x xs | not (elemG x xs) = GADTConsSet x xs -- does infer Provided (Eq a) for ConsSetG
GHC doesn't complain about the lack of signature, does infer pattern ConsSetG :: () => Eq a => a -> GADTSet a -> GADTSet a a Provided constraint, but empty Required.
Inferred (\(ConsSetG x xs) -> x) :: GADTSet p -> p, so the constraint doesn't escape from a "usage site".
Option 2b. define an insert function
insertGADTSet x xs | not (elemG x xs) = GADTConsSet x xs -- (Eq a) inferred
GHC infers insertGADTSet :: Eq a => a -> GADTSet a -> GADTSet a; so the Eq has escaped, even though it doesn't escape from elemG.
Questions
With insertGADTSet, why does the constraint escape? It's only needed for the elemG check, but elemG's type doesn't expose the constraint.
With constructors GADTConsSet, GADTNilSet, there's a constraint wrapped 'all the way down' the data structure. Does that mean the data structure has a bigger memory footprint than with ConsSet_, NilSet_?
With constructors GADTConsSet, GADTNilSet, it's the same type a 'all the way down'. Is the same Eq a dictionary repeated at each node? Or shared?
By comparison, pattern ConsSetC/constructor CSet/Option 1b wraps only a single dictionary(?), so it'll have a smaller memory footprint than a GADTSet structure(?)
insertCSet has a performance hit of unwrapping and wrapping CSets?
ConsSetC2 in the build direction seems to work; there's a performance hit in unwrapping and wrapping CSets? But worse there's a unwrapping/wrapping performance hit in accessing/walking the nodes?
(I'm feeling there's no slam-dunk winner amongst these options for my use case.)
I don't think there is any realistic scenario where it is important that you disallow the creation of an empty set with an "unacceptable" type. It is at least partly because of lack of such realistic scenarios that DatatypeContexts is considered bad practice. Seriously, try to imagine how such a restriction could possibly help avoid real-world programming errors. That is, try to imagine how someone using your types and functions might (1) write an erroneous program that (2) "accidentally" uses a set of, say, functions and yet (3) somehow gets it to type check in a manner that (4) could have been caught if only there'd been an extra Eq constraint on NilSet. As soon as a programmer tries to do anything with that set that makes it non-empty (i.e., anything that needs Eq functionality), it won't type check, so what exactly are you trying to prevent? You want to stop someone who only needs empty sets of functions from using your types? Why? Is it spite? ... It is spite, isn't it?
Getting down to your various options, putting the constraint in a GADT is inappropriate and unnecessary to my mind. The point of constraints in GADTs is to allow destruction to dynamically and/or conditionally bring an instance dictionary into scope, based on a runtime case match. You do not need this functionality. In particular, you do not need the overhead of a dictionary in every one of your Cons nodes as per option 2. However, you also don't need a dictionary in the data type as per option 1(b). It's better to use the normal non-GADT mechanisms of passing dictionaries to functions instead of carrying them around in the data types. I expect you'll be missing many opportunities for specialization and optimization if you try option 1(b). Partly this may be because GADTs are intrinsically harder to optimize, but there's also much less work that's been put into optimizing code using GADTs than code using non-GADTs. Some of your questions suggest you're very concerned about small performance gains. If so, it's generally a good idea to stay well away from GADTs!
Option 1(a) is a reasonable solution. Without the unnecessary Eq constraint on Nil, and folding the insert function into the pattern definition, you get something like:
{-# LANGUAGE PatternSynonyms #-}
data Set a = Nil | Cons_ a (Set a) deriving (Show)
pattern Cons :: (Eq a) => a -> Set a -> Set a
pattern Cons x xs <- Cons_ x xs
where Cons x xs = go xs
where go Nil = Cons_ x xs
go (Cons_ y ys) | x == y = xs
| otherwise = go ys
which seems like a perfectly idiomatic, straightforward, smart constructor implementation using patterns, as designed.
Indeed, it's unfortunately that the constraint applies to destruction, when it isn't really needed. Ideally, GHC would allow constraints for use of Cons as a constructor to be specified separately, instead of assuming they're the combination of the required and provided constraints for destruction.
This would allow us to write something like:
pattern Cons :: a -> Set a -> Set a
pattern Cons x xs <- Cons_ x xs
where Cons :: Eq a => a -> Set a -> Set a -- <== only need Eq here
Cons x Nil = Cons_ x Nil
Cons x rest#(Cons_ y xs) | x == y = rest
| otherwise = Cons_ y (Cons x xs)
and then usages of Cons as a destructor could be constraint-free while uses as a constructor could take advantage of the Eq a constraint. I see this as a limitation of PatternSynonyms rather than an indication that adding unnecessary constraints a la DatatypeContexts is actually good programming practice. It looks like at least a few other people agree that this is a bug not a feature.
To your first four questions:
In option 2(b), insertGADTSet needs an Eq a dictionary to insert into the dictionary slot in the GADTConsSet constructor on the RHS. So, the Eq a constraint comes from the use of the GADTConsSet constructor.
Yes, GADT constraints become additional fields in the data type. In option 2, a pointer to the Eq a dictionary is added to every node in your set.
The dictionary itself is shared, but each node includes its own pointer to the dictionary.
Yes, for the CSet type, there's only one pointer to the dictionary per CSet value.
I believe that option 1b is your best bet. Of course, I may be biased, as I'm the one which suggested it on your other question.
To address the issue you've pointed out with your pattern synonym, let us imagine we don't have pattern synonyms. How might we deconstruct a Cons set?
One way is to write a method with this signature:
openSetC :: CSet a -> (Eq a => a -> CSet a -> r) -> (Eq a => r) -> r
Which says that given:
a CSet a,
a function which takes: a proof that Eq a, an a, and another CSet a, and returns some arbitrary type,
and a function which takes a proof that Eq a and returns the same arbitrary type,
we can produce a value of that arbitrary type. Since the type is arbitrary, we know that the values comes from calling the function, or from the given value of that type. The contract of this function is that it invokes the first function and return its result if and only if the set is ConsSet_, otherwise, if it is NilSet_, it invokes the second function.
If you squint a little, you can see this function is in a sense "equivalent" to pattern matching on CSet. You don't need pattern matching at all anymore; you can do everything with this function that you can do with pattern matching.
It's implementation is quite trivial:
openSetC (CSet (ConsSet_ x xs)) k _ = k x (CSet xs)
openSetC (CSet NilSet_) _ z = z
Consider now a different form of this function, which accomplishes all the same things, but is maybe a bit easier to use.
Note that the type forall r . (a -> r) -> (b -> r) -> r is isomorphic to Either a b. Also note that x0 -> y0 -> r is isomorphic (or close enough) to (x0, y0) -> r. And finally note that C a => r is isomorphic to Dict (C a) -> r where:
data Dict c where Dict :: c => Dict c
If we exploit these isomorphisms, we can write openSetC differently as:
openSetC' :: CSet a -> Either (a, CSet a, Dict (Eq a)) (Dict (Eq a))
openSetC' (CSet (ConsSet_ x xs)) = Left (x, CSet xs, Dict)
openSetC' (CSet NilSet_) = Right Dict
Now the fun part: using ViewPatterns, we can use this function directly to easily write the pattern with the signature you want. It's easy only because we've set up the type of openSetC' to match with the type of the pattern you want:
pattern ConsSetC :: () => Eq a => a -> CSet a -> CSet a
pattern ConsSetC x xs <- (openSetC' -> Left (x, xs, Dict))
-- included for completeness, but the expression form of the pattern synonym is not at issue here
where
ConsSetC x (CSet xs) | not (elemS x xs) = CSet (ConsSet_ x xs)
| otherwise = CSet xs
As for the rest of your questions, I would strongly suggest splitting them up into different posts so they could all have focused answers.

Haskell: "Non type-variable argument in the constraint: Eq Bit" and "No instance for (Eq Bit) arising drom a use of '=='"

data Bit = One
| Zero
deriving Show
type Bits = [Bit]
bits2String :: Bits -> String
bits2String [] = ""
bits2String (x:xs) | x == One = "1" ++ bits2String xs
| x == Zero = "0" ++ bits2String xs
This Code causes following error message:
No instance for (Eq Bit) arising drom a use of '=='
For this error you can find a lot of solutions on SO. They always say you need to add Eq like that:
bits2String :: (Eq Bit) => Bits -> String
bits2String [] = ""
bits2String (x:xs) | x == One = "1" ++ bits2String xs
| x == Zero = "0" ++ bits2String xs
But this doesnt work for me and causes following error
Non type-variable argument in the constraint: Eq Bit
(Use FlexibleContexts to permit this)
{-# LANGUAGE FlexibleContexts #-} doesnt work either.
The original error message is the key one:
No instance for (Eq Bit) arising drom a use of '=='
This arises because you are using the == operator, which is only available for instances of the Eq typeclass - and you haven't given such an instance.
That's easily fixed though. For one you can easily provide the instance manually:
instance Eq Bit where
One == One = True
Zero == Zero = True
_ == _ = False
I wouldn't recommend that you do that though. You can ask Haskell to generate that exact instance for you by simply adding a deriving clause to the type definition. In fact you're already using one, so you can just add Eq to the list of instances you want to derive:
data Bit = One
| Zero
deriving (Show, Eq)
Adding this instance is a good idea in general, because you might well need to compare Bits for equality at some point, especially when working with lists of them - many list functions such as elem depend on Eq instances for their members.
But you can rewrite your bits2String function to not need an Eq instance at all, by pattern matching on the two data constructors:
bits2String :: Bits -> String
bits2String [] = ""
bits2String (One:xs) = "1" ++ bits2String xs
bits2String (Zero:xs) = "0" ++ bits2String xs
In fact, you've basically reimplemented the map function here, so what I would likely do is to define:
bitToChar :: Bit -> Char
bitToChar Zero = '0'
bitToChar One = '1'
(especially as it's the kind of general utility function that you may well want for other things)
and then
bits2String = map bitToChar
None of those require an Eq instance - but it's likely a good idea to derive it anyway, for the reasons I mentioned.
You make use of x == Zero, so of the (==) :: Eq a => a -> a -> Bool function, but you did not make Bit an instance of Eq. You can do so by adding it to the deriving clause, such that Haskell can automatically implement an instance of Eq for your Bit data type:
data Bit = One
| Zero
deriving (Eq, Show)
By default two items are the same if the data constructor is the same, and the parameters (but here your data constructors have no parameters, so it will only check equality of the data constructors).
That being said, you do not need these to be an instance of Eq, you can use pattern matching instead. Indeed:
bits2String :: Bits -> String
bits2String = map f
where f Zero = '0'
f One = '1'
Here we make use of map :: (a -> b) -> [a] -> [b] to convert a list of items to another list by applying a function to each of the items in the original list. Since Bits is a list of Bits, and String is a list of Chars, we can thus map each Bit to a Char to obtain a String of '0's and '1's for the Zero and Ones respectively.

Understanding Haskell Type Class use in Type Declarations

When we have a function that compares two things using the == comparison operator we add something like Eq a => a... to the type declaration; but this doesn't always seem to be the case.
For example, given the following function:
tail' xs = if length xs == 0
then []
else drop 1 xs
We make use of the == comparison operator, so I assumed the correct type decalaration would be:
tail':: (Eq a) => [a] -> [a]
However, running :t tail' tells me that the correct type decalartion is:
tail':: [a] -> [a]
Why is this the case? Why isn't Eq required in the type declaration?
Eq a => t says that a must be an instance of Eq in the type t. A type being an instance of Eq means that == is defined for that type. But in your definition of tail', you never use == on an a, not even by proxy. The actual use of == is in length xs == 0. The type of length xs (and 0) is Int, and Int is already an instance of Eq, so we already know it has == defined. Since you never use == on an a, you don't need an Eq a constraint.
If, however, you had said xs == [], which seems equivalent (both test whether a list is empty), you would have incurred an Eq a constraint. This is because == on [a] requires an Eq a constraint since it uses == on each list's entries to compare the lists. Since you can use length xs == 0 (or, even better, null xs), though, this added constraint is spurious and should be avoided.
(As an aside, drop 1 [] = [] so you don't even need your if, but that isn't relevant to the question asked.)

Choosing the non-empty Monoid

I need a function which will choose a non-empty monoid. For a list this will mean the following behaviour:
> [1] `mor` []
[1]
> [1] `mor` [2]
[1]
> [] `mor` [2]
[2]
Now, I've actually implemented it but am wondering wether there exists some standard alternative, because it seems to be a kind of a common case. Unfortunately Hoogle doesn't help.
Here's my implementation:
mor :: (Eq a, Monoid a) => a -> a -> a
mor a b = if a /= mempty then a else b
If your lists contain at most one element, they're isomorphic to Maybe, and for that there's the "first non empty" monoid: First from Data.Monoid. It's a wrapper around Maybe a values, and mappend returns the first Just value:
import Data.Monoid
main = do
print $ (First $ Just 'a') <> (First $ Just 'b')
print $ (First $ Just 'a') <> (First Nothing)
print $ (First Nothing) <> (First $ Just 'b')
print $ (First Nothing) <> (First Nothing :: First Char)
==> Output:
First {getFirst = Just 'a'}
First {getFirst = Just 'a'}
First {getFirst = Just 'b'}
First {getFirst = Nothing}
Conversion [a] -> Maybe a is achieved using Data.Maybe.listToMaybe.
On a side note: this one does not constrain the typeclass of the wrapped type; in your question, you need an Eq instance to compare for equality with mempty. This comes at the cost of having the Maybe type, of course.
[This is really a long comment rather than an answer]
In my comment, when I said "monoidal things have no notion of introspection" - I meant that you can't perform analysis (pattern matching, equality, <, >, etc.) on monoids. This is obvious of course - the API of Monoids is only unit (mempty) and an operation mappend (more abstractly <>) that takes two monodial things and returns one. The definition of mappend for a type is free to use case analysis, but afterwards all you can do with monoidal things is use the Monoid API.
It's something of a folklore in the Haskell community to avoid inventing things, prefering instead to use objects from mathematics and computer science (including functional programming history). Combining Eq (which needs analysis of is arguments) and Monoid introduces a new class of things - monoids that support enough introspection to allow equality; and at this point there is a reasonable argument that an Eq-Monoid thing goes against the spirit of its Monoid superclass (Monoids are opaque). As this is both a new class of objects and potentially contentious - a standard implementation won't exist.
First, your mor function looks rather suspicious because it requires a Monoid but never uses mappend, and so it is significantly more constrained than necessary.
mor :: (Eq a, Monoid a) => a -> a -> a
mor a b = if a /= mempty then a else b
You could accomplish the same thing with merely a Default constraint:
import Data.Default
mor :: (Eq a, Default a) => a -> a -> a
mor a b = if a /= def then a else b
and I think that any use of Default should also be viewed warily because, as I believe many Haskellers complain, it is a class without principles.
My second thought is that it seems that the data type you're really dealing with here is Maybe (NonEmpty a), not [a], and the Monoid you're actually talking about is First.
import Data.Monoid
morMaybe :: Maybe a -> Maybe a -> Maybe a
morMaybe x y = getFirst (First x <> First y)
And so then we could use that with lists, as in your example, under the (nonEmpty, maybe [] toList) isomorphism between [a] and Maybe (NonEmpty a):
import Data.List.NonEmpty
morList :: [t] -> [t] -> [t]
morList x y = maybe [] toList (nonEmpty x `mor` nonEmpty y)
λ> mor'list [1] []
[1]
λ> mor'list [] [2]
[2]
λ> mor'list [1] [2]
[1]
(I'm sure that somebody more familiar with the lens library could provide a more impressive concise demonstration here, but I don't immediately know how.)
You could extend Monoid with a predicate to test whether an element is an identity.
class Monoid a => TestableMonoid a
where
isMempty :: a -> Bool
morTestable :: a -> a -> a
morTestable x y = if isMempty x then y else x
Not every monoid can have an instance of TestableMonoid, but plenty (including list) can.
instance TestableMonoid [a]
where
isMempty = null
We could even then write a newtype wrapper with a Monoid:
newtype Mor a = Mor { unMor :: a }
instance TestableMonoid a => Monoid (Mor a)
where
mempty = Mor mempty
Mor x `mappend` Mor y = Mor (morTestable x y)
λ> unMor (Mor [1] <> Mor [])
[1]
λ> unMor (Mor [] <> Mor [2])
[2]
λ> unMor (Mor [1] <> Mor [2])
[1]
So that leaves open the question of whether the TestableMonoid class deserves to exist. It certainly seems like a more "algebraically legitimate" class than Default, at least, because we can give it a law that relates it to Monoid:
isEmpty x iff mappend x = id
But I do question whether this actually has any common use cases. As I said earlier, the Monoid constraint is superfluous for your use case because you never mappend. So we should ask, then, can we envision a situation in which one might need both mappend and isMempty, and thus have a legitimate need for a TestableMonoid constraint? It's possible I'm being shortsighted here, but I can't envision a case.
I think this is because of something Stephen Tetley touched on when he said that this "goes against the spirit of its Monoid." Tilt your head at the type signature of mappend with a slightly different parenthesization:
mappend :: a -> (a -> a)
mappend is a mapping from members of a set a to functions a -> a. A monoid is a way of viewing values as functions over those values. The monoid is a view of the world of a only through the window of what these functions let us see. And functions are very limited in what they let us see. The only thing we ever do with them is apply them. We never ask anything else of a function (as Stephen said, we have no introspection into them). So although, yes, you can bolt anything you want onto a subclass, in this case the thing we're bolting on feels very different in character from the base class we are extending, and it feels unlikely that there would be much intersection between the use cases of functions and the use cases of things that have general equality or a predicate like isMempty.
So finally I want to come back around to the simple and precise way to write this: Write code at the value level and stop worrying classes. You don't need Monoid and you don't need Eq, all you need is an additional argument:
morSimple :: (t -> Bool) -- ^ Determine whether a value should be discarded
-> t -> t -> t
morSimple f x y = if f x then y else x
λ> morSimple null [1] []
[1]
λ> morSimple null [1] [2]
[1]
λ> morSimple null [] [2]
[2]

Get a list of the instances in a type class in Haskell

Is there a way to programmatically get a list of instances of a type class?
It strikes me that the compiler must know this information in order to type check and compile the code, so is there some way to tell the compiler: hey, you know those instances of that class, please put a list of them right here (as strings or whatever some representation of them).
You can generate the instances in scope for a given type class using Template Haskell.
import Language.Haskell.TH
-- get a list of instances
getInstances :: Name -> Q [ClassInstance]
getInstances typ = do
ClassI _ instances <- reify typ
return instances
-- convert the list of instances into an Exp so they can be displayed in GHCi
showInstances :: Name -> Q Exp
showInstances typ = do
ins <- getInstances typ
return . LitE . stringL $ show ins
Running this in GHCi:
*Main> $(showInstances ''Num)
"[ClassInstance {ci_dfun = GHC.Num.$fNumInteger, ci_tvs = [], ci_cxt = [], ci_cls = GHC.Num.Num, ci_tys = [ConT GHC.Integer.Type.Integer]},ClassInstance {ci_dfun = GHC.Num.$fNumInt, ci_tvs = [], ci_cxt = [], ci_cls = GHC.Num.Num, ci_tys = [ConT GHC.Types.Int]},ClassInstance {ci_dfun = GHC.Float.$fNumFloat, ci_tvs = [], ci_cxt = [], ci_cls = GHC.Num.Num, ci_tys = [ConT GHC.Types.Float]},ClassInstance {ci_dfun = GHC.Float.$fNumDouble, ci_tvs = [], ci_cxt = [], ci_cls = GHC.Num.Num, ci_tys = [ConT GHC.Types.Double]}]"
Another useful technique is showing all instances in scope for a given type class using GHCi.
Prelude> :info Num
class (Eq a, Show a) => Num a where
(+) :: a -> a -> a
(*) :: a -> a -> a
(-) :: a -> a -> a
negate :: a -> a
abs :: a -> a
signum :: a -> a
fromInteger :: Integer -> a
-- Defined in GHC.Num
instance Num Integer -- Defined in GHC.Num
instance Num Int -- Defined in GHC.Num
instance Num Float -- Defined in GHC.Float
instance Num Double -- Defined in GHC.Float
Edit: The important thing to know is that the compiler is only aware of type classes in scope in any given module (or at the ghci prompt, etc.). So if you call the showInstances TH function with no imports, you'll only get instances from the Prelude. If you have other modules in scope, e.g. Data.Word, then you'll see all those instances too.
See the template haskell documentation: http://hackage.haskell.org/packages/archive/template-haskell/2.5.0.0/doc/html/Language-Haskell-TH.html
Using reify, you can get an Info record, which for a class includes its list of instances. You can also use isClassInstance and classInstances directly.
This is going to run into a lot of problems as soon as you get instance declarations like
instance Eq a => Eq [a] where
[] == [] = True
(x:xs) == (y:ys) = x == y && xs == ys
_ == _ = False
and
instance (Eq a,Eq b) => Eq (a,b) where
(a1,b1) == (a2,b2) = a1 == a2 && b1 == b2
along with a single concrete instance (e.g. instance Eq Bool).
You'll get an infinite list of instances for Eq - Bool,[Bool],[[Bool]],[[[Bool]]] and so on, (Bool,Bool), ((Bool,Bool),Bool), (((Bool,Bool),Bool),Bool) etcetera, along with various combinations of these such as ([((Bool,[Bool]),Bool)],Bool) and so forth. It's not clear how to represent these in a String; even a list of TypeRep would require some pretty smart enumeration.
The compiler can (try to) deduce whether a type is an instance of Eq for any given type, but it doesn't read in all the instance declarations in scope and then just starts deducing all possible instances, since that will never finish!
The important question is of course, what do you need this for?
I guess, it's not possible. I explain you the implementation of typeclasses (for GHC), from it, you can see, that the compiler has no need to know which types are instance of a typeclass. It only has to know, whether a specific type is instance or not.
A typeclass will be translated into a datatype. As an example, let's take Eq:
class Eq a where
(==),(/=) :: a -> a -> Bool
The typeclass will be translated into a kind of dictionary, containing all its functions:
data Eq a = Eq {
(==) :: a -> a -> Bool,
(/=) :: a -> a -> Bool
}
Each typeclass constraint is then translated into an extra argument containing the dictionary:
elem :: Eq a => a -> [a] -> Bool
elem _ [] = False
elem a (x:xs) | x == a = True
| otherwise = elem a xs
becomes:
elem :: Eq a -> a -> [a] -> Bool
elem _ _ [] = False
elem eq a (x:xs) | (==) eq x a = True
| otherwise = elem eq a xs
The important thing is, that the dictionary will be passed at runtime. Imagine, your project contains many modules. GHC doesn't have to check all the modules for instances, it just has to look up, whether an instance is defined anywhere.
But if you have the source available, I guess an old-style grep for the instances would be sufficient.
It is not possible to automatically do this for existing classes. For your own class and instances thereof you could do it. You would need to declare everything via Template Haskell (or perhaps the quasi-quoting) and it would automatically generate some strange data structure that encodes the declared instances. Defining the strange data structure and making Template Haskell do this are details left to whomever has a use case for them.
Perhaps you could add some Template Haskell or other magic to your build to include all the source files as text available at run-time (c.f. program quine). Then your program would 'grep itself'...

Resources