Using data constructor as a function parameter - haskell

I am making my way through "Haskell Programming..." and, in Chapter 10, have been working with a toy database. The database is defined as:
data DatabaseItem = DBString String
| DBNumber Integer
| DBDate UTCTime
deriving (Eq, Ord, Show)
and, given a database of the form [databaseItem], I am asked to write a function
dbNumberFilter :: [DatabaseItem] -> [Integer]
that takes a list of DatabaseItems, filters them for DBNumbers, and returns a list the of Integer values stored in them.
I solved that with:
dbNumberFilter db = foldr selectDBNumber [] db
where
selectDBNumber (DBNumber a) b = a : b
selectDBNumber _ b = b
Obviously, I can write an almost identical to extract Strings or UTCTTimes, but I am wondering if there is a way to create a generic filter that can extract a list of Integers, Strings, by passing the filter a chosen data constructor. Something like:
dbGenericFilter :: (a -> DataBaseItem) -> [DatabaseItem] -> [a]
dbGenericFilter DBICon db = foldr selectDBDate [] db
where
selectDBDate (DBICon a) b = a : b
selectDBDate _ b = b
where by passing DBString, DBNumber, or DBDate in the DBICon parameter, will return a list of Strings, Integers, or UTCTimes respectively.
I can't get the above, or any variation of it that I can think of, to work. But is there a way of achieving this effect?

You can't write a function so generic that it just takes a constructor as its first argument and then does what you want. Pattern matches are not first class in Haskell - you can't pass them around as arguments. But there are things you could do to write this more simply.
One approach that isn't really any more generic, but is certainly shorter, is to make use of the fact that a failed pattern match in a list comprehension skips the item:
dbNumberFilter db = [n | DBNumber n <- db]
If you prefer to write something generic, such that dbNUmberFilter = genericFilter x for some x, you can extract the concept of "try to match a DBNumber" into a function:
import Data.Maybe (mapMaybe)
genericFilter :: (DatabaseItem -> Maybe a) -> [DatabaseItem] -> [a]
genericFilter = mapMaybe
dbNumberFilter = genericFilter getNumber
where getNumber (DBNumber n) = Just n
getNumber _ = Nothing
Another somewhat relevant generic thing you could do would be to define the catamorphism for your type, which is a way of abstracting all possible pattern matches for your type into a single function:
dbCata :: (String -> a)
-> (Integer -> a)
-> (UTCTime -> a)
-> DatabaseItem -> a
dbCata s i t (DBString x) = s x
dbCata s i t (DBNumber x) = i x
dbCata s i t (DBDate x) = t x
Then you can write dbNumberFilter with three function arguments instead of a pattern match:
dbNumberFilter :: [DatabaseItem] -> [Integer]
dbNumberFilter = (>>= dbCata mempty pure mempty)

Related

Getting all function arguments in haskel as list

Is there a way in haskell to get all function arguments as a list.
Let's supose we have the following program, where we want to add the two smaller numbers and then subtract the largest. Suppose, we can't change the function definition of foo :: Int -> Int -> Int -> Int. Is there a way to get all function arguments as a list, other than constructing a new list and add all arguments as an element of said list? More importantly, is there a general way of doing this independent of the number of arguments?
Example:
module Foo where
import Data.List
foo :: Int -> Int -> Int -> Int
foo a b c = result!!0 + result!!1 - result!!2 where result = sort ([a, b, c])
is there a general way of doing this independent of the number of arguments?
Not really; at least it's not worth it. First off, this entire idea isn't very useful because lists are homogeneous: all elements must have the same type, so it only works for the rather unusual special case of functions which only take arguments of a single type.
Even then, the problem is that “number of arguments” isn't really a sensible concept in Haskell, because as Willem Van Onsem commented, all functions really only have one argument (further arguments are actually only given to the result of the first application, which has again function type).
That said, at least for a single argument- and final-result type, it is quite easy to pack any number of arguments into a list:
{-# LANGUAGE FlexibleInstances #-}
class UsingList f where
usingList :: ([Int] -> Int) -> f
instance UsingList Int where
usingList f = f []
instance UsingList r => UsingList (Int -> r) where
usingList f a = usingList (f . (a:))
foo :: Int -> Int -> Int -> Int
foo = usingList $ (\[α,β,γ] -> α + β - γ) . sort
It's also possible to make this work for any type of the arguments, using type families or a multi-param type class. What's not so simple though is to write it once and for all with variable type of the final result. The reason being, that would also have to handle a function as the type of final result. But then, that could also be intepreted as “we still need to add one more argument to the list”!
With all respect, I would disagree with #leftaroundabout's answer above. Something being
unusual is not a reason to shun it as unworthy.
It is correct that you would not be able to define a polymorphic variadic list constructor
without type annotations. However, we're not usually dealing with Haskell 98, where type
annotations were never required. With Dependent Haskell just around the corner, some
familiarity with non-trivial type annotations is becoming vital.
So, let's take a shot at this, disregarding worthiness considerations.
One way to define a function that does not seem to admit a single type is to make it a method of a
suitably constructed class. Many a trick involving type classes were devised by cunning
Haskellers, starting at least as early as 15 years ago. Even if we don't understand their
type wizardry in all its depth, we may still try our hand with a similar approach.
Let us first try to obtain a method for summing any number of Integers. That means repeatedly
applying a function like (+), with a uniform type such as a -> a -> a. Here's one way to do
it:
class Eval a where
eval :: Integer -> a
instance (Eval a) => Eval (Integer -> a) where
eval i = \y -> eval (i + y)
instance Eval Integer where
eval i = i
And this is the extract from repl:
λ eval 1 2 3 :: Integer
6
Notice that we can't do without explicit type annotation, because the very idea of our approach is
that an expression eval x1 ... xn may either be a function that waits for yet another argument,
or a final value.
One generalization now is to actually make a list of values. The science tells us that
we may derive any monoid from a list. Indeed, insofar as sum is a monoid, we may turn arguments to
a list, then sum it and obtain the same result as above.
Here's how we can go about turning arguments of our method to a list:
class Eval a where
eval2 :: [Integer] -> Integer -> a
instance (Eval a) => Eval (Integer -> a) where
eval2 is i = \j -> eval2 (i:is) j
instance Eval [Integer] where
eval2 is i = i:is
This is how it would work:
λ eval2 [] 1 2 3 4 5 :: [Integer]
[5,4,3,2,1]
Unfortunately, we have to make eval binary, rather than unary, because it now has to compose two
different things: a (possibly empty) list of values and the next value to put in. Notice how it's
similar to the usual foldr:
λ foldr (:) [] [1,2,3,4,5]
[1,2,3,4,5]
The next generalization we'd like to have is allowing arbitrary types inside the list. It's a bit
tricky, as we have to make Eval a 2-parameter type class:
class Eval a i where
eval2 :: [i] -> i -> a
instance (Eval a i) => Eval (i -> a) i where
eval2 is i = \j -> eval2 (i:is) j
instance Eval [i] i where
eval2 is i = i:is
It works as the previous with Integers, but it can also carry any other type, even a function:
(I'm sorry for the messy example. I had to show a function somehow.)
λ ($ 10) <$> (eval2 [] (+1) (subtract 2) (*3) (^4) :: [Integer -> Integer])
[10000,30,8,11]
So far so good: we can convert any number of arguments into a list. However, it will be hard to
compose this function with the one that would do useful work with the resulting list, because
composition only admits unary functions − with some trickery, binary ones, but in no way the
variadic. Seems like we'll have to define our own way to compose functions. That's how I see it:
class Ap a i r where
apply :: ([i] -> r) -> [i] -> i -> a
apply', ($...) :: ([i] -> r) -> i -> a
($...) = apply'
instance Ap a i r => Ap (i -> a) i r where
apply f xs x = \y -> apply f (x:xs) y
apply' f x = \y -> apply f [x] y
instance Ap r i r where
apply f xs x = f $ x:xs
apply' f x = f [x]
Now we can write our desired function as an application of a list-admitting function to any number
of arguments:
foo' :: (Num r, Ord r, Ap a r r) => r -> a
foo' = (g $...)
where f = (\result -> (result !! 0) + (result !! 1) - (result !! 2))
g = f . sort
You'll still have to type annotate it at every call site, like this:
λ foo' 4 5 10 :: Integer
-1
− But so far, that's the best I can do.
The more I study Haskell, the more I am certain that nothing is impossible.

data type with a default field and that needs a function that works with it

Say, I have a data type
data FooBar a = Foo String Char [a]
| Bar String Int [a]
I need to create values of this type and give empty list as the second field:
Foo "hello" 'a' []
or
Bar "world" 1 []
1) I do this everywhere in my code and I think it would be nice if I could omit the empty list part somehow and have the empty list assigned implicitly. Is this possible? Something similar to default function arguments in other languages.
2) Because of this [] "default" value, I often need to have a partial constructor application that results in a function that takes the first two values:
mkFoo x y = Foo x y []
mkBar x y = Bar x y []
Is there a "better" (more idiomatic, etc) way to do it? to avoid defining new functions?
3) I need a way to add things to the list:
add (Foo u v xs) x = Foo u v (x:xs)
add (Bar u v xs) x = Bar u v (x:xs)
Is this how it is done idiomatically? Just a general purpose function?
As you see I am a beginner, so maybe these questions make little sense. Hope not.
I'll address your questions one by one.
Default arguments do not exist in Haskell. They are simply not worth the added complexity and loss of compositionally. Being a functional language, you do a lot more function manipulation in Haskell, so funkiness like default arguments would be tough to handle.
One thing I didn't realize when I started Haskell is that data constructors are functions just like everything else. In your example,
Foo :: String -> Char -> [a] -> FooBar a
Thus you can write functions for filling in various arguments of other functions, and then those functions will work with Foo or Bar or whatever.
fill1 :: a -> (a -> b) -> b
fill1 a f = f a
--Note that fill1 = flip ($)
fill2 :: b -> (a -> b -> c) -> (a -> c)
--Equivalently, fill2 :: b -> (a -> b -> c) -> a -> c
fill2 b f = \a -> f a b
fill3 :: c -> (a -> b -> c -> d) -> (a -> b -> d)
fill3 c f = \a b -> f a b c
fill3Empty :: (a -> b -> [c] -> d) -> (a -> b -> d)
fill3Empty f = fill3 [] f
--Now, we can write
> fill3Empty Foo x y
Foo x y []
The lens package provides elegant solutions to questions like this. However, you can tell at a glance that this package is enormously complicated. Here is the net result of how you would call the lens package:
_list :: Lens (FooBar a) (FooBar b) [a] [b]
_list = lens getter setter
where getter (Foo _ _ as) = as
getter (Bar _ _ as) = as
setter (Foo s c _) bs = Foo s c bs
setter (Bar s i _) bs = Bar s i bs
Now we can do
> over _list (3:) (Foo "ab" 'c' [2,1])
Foo "ab" 'c' [3,2,1]
Some explanation: the lens function produces a Lens type when given a getter and a setter for some type. Lens s t a b is a type that says "s holds an a and t holds a b. Thus, if you give me a function a -> b, I can give you a function s -> t". That is exactly what over does: you provide it a lens and a function (in our case, (3:) was a function that adds 3 to the front of a List) and it applies the function "where the lens indicates". This is very similar to a functor, however, we have significantly more freedom (in this example, the functor instance would be obligated to change every element of the lists, not operate on the lists themselves).
Note that our new _list lens is very generic: it works equally well over Foo and Bar and the lens package provides many functions other than over for doing magical things.
The idiomatic thing is to take those parameters of a function or constructor that you commonly want to partially apply, and move them toward the beginning:
data FooBar a = Foo [a] String Char
| Bar [a] String Int
foo :: String -> Char -> FooBar a
foo = Foo []
bar :: String -> Int -> FooBar a
bar = Bar []
Similarly, reordering the parameters to add lets you partially apply add to get functions of type FooBar a -> FooBar a, which can be easily composed:
add :: a -> FooBar a -> FooBar a
add x (Foo xs u v) = Foo (x:xs) u v
add123 :: FooBar Int -> FooBar Int
add123 = add 1 . add 2 . add 3
add123 (foo "bar" 42) == Foo [1, 2, 3] "bar" 42
(2) and (3) are perfectly normal and idiomatic ways of doing such things. About (2) in particular, one expression you will occasionally hear is "smart constructor". That just means a function like your mkFoo/mkBar that produces a FooBar a (or a Maybe (FooBar a) etc.) with some extra logic to ensure only reasonable values can be constructed.
Here are some additional tricks that might (or might not!) make sense, depending on what you are trying to do with FooBar.
If you use Foo values and Barvalues in similar ways most of the time (i.e. the difference between having the Char field and the Int one is a minor detail), it makes sense to factor out the similarities and use a single constructor:
data FooBar a = FooBar String FooBarTag [a]
data FooBarTag = Foo Char | Bar Int
Beyond avoiding case analysis when you don't care about the FooBarTag, that allows you to safely use record syntax (records and types with multiple constructors do not mix well).
data FooBar a = FooBar
{ fooBarName :: String
, fooBarTag :: FooBarTag
, fooBarList :: [a]
}
Records allow you to use the fields without having to pattern match the whole thing.
If there are sensible defaults for all fields in a FooBar, you can go one step beyond mkFoo-like constructors and define a default value.
defaultFooBar :: FooBar a
defaultFooBar = FooBar
{ fooBarName = ""
, fooBarTag = Bar 0
, fooBarList = []
}
You don't need records to use a default, but they allow overriding default fields conveniently.
myFooBar = defaultFooBar
{ fooBarTag = Foo 'x'
}
If you ever get tired of typing long names for the defaults over and over, consider the data-default package:
instance Default (FooBar a) where
def = defaultFooBar
myFooBar = def { fooBarTag = Foo 'x' }
Do note that a significant number of people do not like the Default class, and not without reason. Still, for types which are very specific to your application (e.g. configuration settings) Default is perfectly fine IMO.
Finally, updating record fields can be messy. If you end up annoyed by that, you will find lens very useful. Note that it is a big library, and it might be a little overwhelming to a beginner, so take a deep breath beforehand. Here is a small sample:
{-# LANGUAGE TemplateHaskell #-} -- At the top of the file. Needed for makeLenses.
import Control.Lens
-- Note the underscores.
-- If you are going to use lenses, it is sensible not to export the field names.
data FooBar a = FooBar
{ _fooBarName :: String
, _fooBarTag :: FooBarTag
, _fooBarList :: [a]
}
makeLenses ''FooBar -- Defines lenses for the fields automatically.
defaultFooBar :: FooBar a
defaultFooBar = FooBar
{ _fooBarName = ""
, _fooBarTag = Bar 0
, _fooBarList = []
}
-- Using a lens (fooBarTag) to set a field without record syntax.
-- Note the lack of underscores in the name of the lens.
myFooBar = set fooBarTag (Foo 'x') defaultFooBar
-- Using a lens to access a field.
myTag = view fooBarTag myFooBar -- Results in Foo 'x'
-- Using a lens (fooBarList) to modify a field.
add :: a -> FooBar a -> FooBar a
add x fb = over fooBarList (x :) fb
-- set, view and over have operator equivalents, (.~). (^.) and (%~) respectively.
-- Note that (^.) is flipped with respect to view.
Here is a gentle introduction to lens which focuses on aspects I have not demonstrated here, specially in how nicely lenses can be composed.

What type signature do I need to allow a list of functions to be converted to haskell code? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Why is such a function definition not allowed in haskell?
I made a haskell function called funlist. What it does is it takes a starting value, and a list of functions, and applies all of the functions in the list to the starting value.
funlist thing [function] = function thing
funlist thing (function:functions) = funlist (function thing) functions
funlist _ _ = error "need a list of functions"
The problem with this function is that it has a type of funlist :: t -> [t -> t] -> t. That type means that while ghc will allow a list of functions that don't convert the starting value to a completely different type (e.g [sin,cos,tan] will be allowed), a function that converts the starting value to a different type (e.g show) will generate an error because that function doesn't match the type signature.
This isn't how the function should work. It should be able to take a list of functions that change the starting values type (e.g. [sin,show]). This function basically converts funlist 5 [sin,cos,tan,isInfinite,show] to show $ isInfinite $ tan $ cos $ sin $ 5, and while the latter works, the former doesn't.
Is there any way that I can get this function to work properly?
EDIT: I know about . and >>>, I'm just wondering if there's a way to make this work.
You can write what you want with a GADT:
{-# LANGUAGE GADTs #-}
module Funlist where
data F x y where
Id :: F a a
Ap :: (a->b) -> F b c -> F a c
-- A very round about way to write f x = x + x
f1 :: Int -> Char
f1 = toEnum
f2 :: Char -> String
f2 x = x:x:[]
f3 :: String -> [Int]
f3 = map fromEnum
f4 :: [Int] -> Integer
f4 = foldr (+) 0 . map toInteger
f_list :: F Int Integer
f_list = Ap f1 (Ap f2 (Ap f3 (Ap f4 Id)))
ap :: F a b -> a -> b
ap Id x = x
ap (Ap f gs) x = ap gs (f x)
Now ap f_list 65 is 130
This does not work with normal functions/normal lists in Haskell, since it requires a dynamically typed language, and not a statically typed language like Haskell. The funlist function can't have a different type depending on what the contents of the function list is at runtime; its type must be known at compile-time. Further, the compiler must be able to check that the function chain is valid, so that you can't use the list [tan, show, sin] for example.
There are two solutions to this problem.
You can either use heterogenous lists. These lists can store lists where each element is a different type. You can then check the constraint that each element must be a function and that one elements return type must be the next function's parameter type. This can become very difficult very quickly.
You can also use Data.Dynamic to let your functions take and return dynamic types. You have to perform some dynamic type casts in that case.
If all you're going to do with this list of functions is apply them to a single value in a pipeline, then instead of writing and calling your funlist function, do this:
show . isInfinite . tan . cos . sin $ 5
or, if you don't want the list reversed in your code, do this:
import Control.Arrow (>>>)
(sin >>> cos >>> tan >>> isInfinite >>> show) 5
Functions in Haskell, in general, have types that look like a -> b, for some choice of a and b. In your case, you have a list [f0, ..., fn] of functions, and you want to compute this:
funlist [f0, ..., fn] x == f0 (funlist [f1, ..., fn] x)
== f0 (f1 (funlist [f2, ..., fn] x))
...
== f0 (f1 (... (fn x)))
The t -> t problem you're having is a consequence of these two things:
This computation requires the argument type of f0 to be the return type of f1, the argument type of f1 to be the return type of f2, and so on: f0 :: y -> z, f1 :: x -> y, ..., fn :: a -> b.
But you're putting all those functions in a list, and all the elements of a list in Haskell must have the same type.
These two, taken together, imply that the list of functions used in funlist must have type [t -> t], because that's the only way both conditions can be met at the same time.
Other than that, dave4420's answer is the best simple answer, IMO: use function composition. If you can't use it because the computation to be done is only known at runtime, then you want to have some data structure more complex than the list to represent the possible computations. Chris Kuklewicz presents a very generic solution for that, but I'd normally do something custom-made for the specific problem area at hand.
Also good to know that your funlist can be written like this:
funlist :: a -> [a -> a] -> a
funlist x fs = foldr (.) id fs x
Short answer: No, there's no way to do what you want with lists (in a sensible way, at least).
The reason is that lists in Haskell are always homogenous, i.e. each element of a list must have the same type. The functions you want to put to the list have types:
sin :: Floating a => a -> a
isInfinite :: Floating b => b -> Bool
show :: Show c => c -> String
So you can't just put the functions in the same list. Your two main options are to:
Use a structure other than list (e.g. HList or a custom GADT)
Use dynamic typing
Since the other answers already gave GADT examples, here's how you could implement your function using dynamic types:
import Data.Dynamic
funlist :: Dynamic -> [Dynamic] -> Dynamic
funlist thing (function:functions) = funlist (dynApp function thing) functions
funlist thing [] = thing
However, using dynamic types causes some boilerplate, because you have to convert between static and dynamic types. So, to call the function, you'd need to write
funlist (toDyn 5) [toDyn sin, toDyn cos, toDyn tan, toDyn isInfinite, toDyn show]
And unfortunately, even that is not enough. The next problem is that dynamic values must have homomorphic types, so for example instead of the function show :: Show a => a -> String you need to manually specify e.g. the concrete type show :: Bool -> String, so the above becomes:
funlist (toDyn (5::Double)) [toDyn sin, toDyn cos, toDyn tan, toDyn isInfinite,
toDyn (show :: Bool -> String)]
What's more, the result of the function is another dynamic value, so we need to convert it back to a static value if we want to use it in regular functions.
fromDyn (funlist (toDyn (5::Double)) [toDyn sin, toDyn cos, toDyn tan,
toDyn isInfinite, toDyn (show :: Bool -> String)]) ""
What you want works in Haskell, but it's not a list. It is a function composition and can actually be wrapped in a GADT:
import Control.Arrow
import Control.Category
import Prelude hiding ((.), id)
data Chain :: * -> * -> * where
Chain :: (a -> c) -> Chain c b -> Chain a b
Id :: Chain a a
apply :: Chain a b -> a -> b
apply (Chain f k) x = apply k (f x)
apply Id x = x
Now you can inspect the structure of the function chain to some extent. There isn't much you can find out, but you can add further meta information to the Chain constructor, if you need more.
The type also forms an interesting category that preserves the additional information:
instance Category Chain where
id = Id
Id . c = c
c . Id = c
c2 . Chain f1 k1 = Chain f1 (c2 . k1)
instance Arrow Chain where
arr f = Chain f Id
first (Chain f c) = Chain (first f) (first c)
first Id = Id
There where some answers using GADTs, which is a good way to do such things. What I want to add here is that the structure used in these answers already exists in a more general fashion: it's called a thrist ("type threaded list"):
Prelude Data.Thrist> let fs = Cons (show :: Char -> String) (Cons length Nil)
Prelude Data.Thrist> let f = foldl1Thrist (flip (.)) fs
Prelude Data.Thrist> :t fs
fs :: Thrist (->) Char Int
Prelude Data.Thrist> :t f
f :: Char -> Int
Prelude Data.Thrist> f 'a'
3
Of course, you could also use foldl1Thrist (>>>) fs instead. Note that thrists form a category, an arrow and a monoid (with appendThrist).

Sort by constructor ignoring (part of) value

Suppose I have
data Foo = A String Int | B Int
I want to take an xs :: [Foo] and sort it such that all the As are at the beginning, sorted by their strings, but with the ints in the order they appeared in the list, and then have all the Bs at the end, in the same order they appeared.
In particular, I want to create a new list containg the first A of each string and the first B.
I did this by defining a function taking Foos to (Int, String)s and using sortBy and groupBy.
Is there a cleaner way to do this? Preferably one that generalizes to at least 10 constructors.
Typeable, maybe? Something else that's nicer?
EDIT: This is used for processing a list of Foos that is used elsewhere. There is already an Ord instance which is the normal ordering.
You can use
sortBy (comparing foo)
where foo is a function that extracts the interesting parts into something comparable (e.g. Ints).
In the example, since you want the As sorted by their Strings, a mapping to Int with the desired properties would be too complicated, so we use a compound target type.
foo (A s _) = (0,s)
foo (B _) = (1,"")
would be a possible helper. This is more or less equivalent to Tikhon Jelvis' suggestion, but it leaves space for the natural Ord instance.
To make it easier to build comparison function for ADTs with large number of constructors, you can map values to their constructor index with SYB:
{-# LANGUAGE DeriveDataTypeable #-}
import Data.Generics
data Foo = A String Int | B Int deriving (Show, Eq, Typeable, Data)
cIndex :: Data a => a -> Int
cIndex = constrIndex . toConstr
Example:
*Main Data.Generics> cIndex $ A "foo" 42
1
*Main Data.Generics> cIndex $ B 0
2
Edit:After re-reading your question, I think the best option is to make Foo an instance of Ord. I do not think there is any way to do this automatically that will act the way you want (just using deriving will create different behavior).
Once Foo is an instance of Ord, you can just use sort from Data.List.
In your exact example, you can do something like this:
data Foo = A String Int | B Int deriving (Eq)
instance Ord Foo where
(A _ _) <= (B _) = True
(A s _) <= (A s' _) = s <= s'
(B _) <= (B _) = True
When something is an instance of Ord, it means the data type has some ordering. Once we know how to order something, we can use a bunch of existing functions (like sort) on it and it will behave how you want. Anything in Ord has to be part of Eq, which is what the deriving (Eq) bit does automatically.
You can also derive Ord. However, the behavior will not be exactly what you want--it will order by all of the fields if it has to (e.g. it will put As with the same string in order by their integers).
Further edit: I was thinking about it some more and realized my solution is probably semantically wrong.
An Ord instance is a statement about your whole data type. For example, I'm saying that Bs are always equal with each other when the derived Eq instance says otherwise.
If the data your representing always behaves like this (that is, Bs are all equal and As with the same string are all equal) then an Ord instance makes sense. Otherwise, you should not actually do this.
However, you can do something almost exactly like this: write your own special compare function (Foo -> Foo -> Ordering) that encapsulates exactly what you want to do then use sortBy. This properly codifies that your particular sorting is special rather than the natural ordering of the data type.
You could use some template haskell to fill in the missing transitive cases. The mkTransitiveLt creates the transitive closure of the given cases (if you order them least to greatest). This gives you a working less-than, which can be turned into a function that returns an Ordering.
{-# LANGUAGE TemplateHaskell #-}
import MkTransitiveLt
import Data.List (sortBy)
data Foo = A String Int | B Int | C | D | E deriving(Show)
cmp a b = $(mkTransitiveLt [|
case (a, b) of
(A _ _, B _) -> True
(B _, C) -> True
(C, D) -> True
(D, E) -> True
(A s _, A s' _) -> s < s'
otherwise -> False|])
lt2Ord f a b =
case (f a b, f b a) of
(True, _) -> LT
(_, True) -> GT
otherwise -> EQ
main = print $ sortBy (lt2Ord cmp) [A "Z" 1, A "A" 1, B 1, A "A" 0, C]
Generates:
[A "A" 1,A "A" 0,A "Z" 1,B 1,C]
mkTransitiveLt must be defined in a separate module:
module MkTransitiveLt (mkTransitiveLt)
where
import Language.Haskell.TH
mkTransitiveLt :: ExpQ -> ExpQ
mkTransitiveLt eq = do
CaseE e ms <- eq
return . CaseE e . reverse . foldl go [] $ ms
where
go ms m#(Match (TupP [a, b]) body decls) = (m:ms) ++
[Match (TupP [x, b]) body decls | Match (TupP [x, y]) _ _ <- ms, y == a]
go ms m = m:ms

Haskell data structures oddity

I've been attempting to write a small file to try out a bag-like data structure. So far my code is as follows:
data Fruit = Apple | Banana | Pear deriving (Eq, Show)
data Bag a = EmptyBag | Contents [(a, Integer)]
emptyBag :: Bag a
emptyBag = EmptyBag
unwrap :: [a] -> a
unwrap [x] = x
isObject theObject (obj, inte) = theObject == obj
count :: Bag a -> a -> Integer
count (Contents [xs]) theObject = snd (unwrap (filter (isObject theObject) [xs]))
count EmptyBag _ = 0
But when I try and run it I get the error
Could not deduce (Eq a) from the context ()
arising from a use of 'isObject' at ....
Whereas when I take the count function out and call
snd(unwrap(filter (isObject Banana) [(Apple,1),(Banana,2)]))
it happily returns 2.
Any clues on why this is, or advice on writing this kind of data structure would be much appreciated.
(==) can only be used in a context that includes Eq, but when you declared count you didn't include that context. If I'm reading correctly, that would be
count :: Eq a => Bag a -> a -> Integer
If you declare count without including the type, you can ask ghci for the inferred type; or just ask for the inferred type of snd (unwrap (filter (isObject Banana) [(Apple,1),(Banana,2)]))

Resources