If pattern matching with `Maybe a` result - haskell

Following code illustrates my intention. I want to pattern match, if it doesn't result is Nothing, if matches result is Just something
data MyData =
A Int
| B String
| C
ifA (A i) = Just i
ifA _ = Nothing
ifB (B str) = Just str
ifB _ = Nothing
ifC C = Just ()
ifC _ = Nothing
mbMult3 i = Just (i*3)
concWorld str = Just (str ++ "World")
example1 v = ifA v >>= mbMult3
example2 v = ifB v >>= concWorld
-- example2 (B "Hello ,") == Just "Hello, World"
-- example2 (A 3) == Nothing
Are there other ways to do ifA ifB ifC.
Edit:
I suspect that lens library might have something. But I know nothing about lens for now.
Updated ifC

Prisms† from the lens package model this. You can generate prisms for your type using makePrisms, then use ^? (or its prefix equivalent, preview) to access members of the sum type, producing Nothing if a different value is provided:
{-# LANGUAGE TemplateHaskell #-}
import Control.Lens
data MyData
= A Int
| B String
| C
deriving (Show)
makePrisms ''MyData
ghci> A 42 ^? _A
Just 42
ghci> A 42 ^? _B
Nothing
ghci> C ^? _C
Just ()
The nice thing about prisms is that they compose with other optics (e.g. lenses, folds, and traversals), as well as use them to traverse through nested sum types by composing prisms:
ghci> (A 42, C) ^? _1._A
Just 42
ghci> (B "hello", C) ^? _1._A
Nothing
ghci> Just (A 42) ^? _Just._A
Just 42
ghci> Just (B "hello") ^? _Just._A
Nothing
ghci> Nothing ^? _Just._A
Nothing
The lens package is fairly complicated, and explaining all of its features is well outside the scope of this answer. If you don’t need much of it, your solution is probably fine. But if you find yourself writing that sort of code a lot, it’s likely that lens can help, as long as you’re willing to accept the steep learning curve and often-confusing type errors.
† More generally, ^? works on any Fold that produces zero or one value (or more, it just ignores all but the first one), but prisms are specifically designed with sum types in mind, so they are more relevant here.

Here's a cute idiom that I use from time to time, since I'm not yet up on my lenses.
{-# LANGUAGE MonadComprehensions #-}
example1 v = [ x | A x <- pure v ] >>= mbMult3

Related

Printing Dynamic Data

I have a system in haskell that uses Data.Dynamic and Type.Reflection to perform inference and calculations. I would like to be able to print the results.
Printing is easy when the type is supplied e.g
foo :: Dynamic -> String
foo dyn = case tyConName . someTypeRepTyCon . dynTypeRep $ dyn of
"Int" -> show $ fromDyn dyn (0 :: Int)
"Bool" -> show $ fromDyn dyn True
_ -> "no chance"
But if I want to be able to print tuples, I would have to add a new line for each e.g (Int, Bool), (Bool, Int), (Char, Int, Banana) ....
With the addition of more primitives and larger tuples this quickly becomes impractical.
Is there an algorithmic way to generate strings for this dynamic data, specifically for tuples and lists.
I like the main idea of the other answer, but it seems to get where it's going in a fairly roundabout way. Here's how I would style the same idea:
{-# LANGUAGE ViewPatterns #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE GADTs #-}
import Type.Reflection
import Data.Dynamic
showDyn :: Dynamic -> String
showDyn (Dynamic (App (App (eqTypeRep (typeRep #(,)) -> Just HRefl) ta) tb) (va, vb))
= concat [ "DynamicPair("
, showDyn (Dynamic ta va)
, ","
, showDyn (Dynamic tb vb)
, ")"
]
showDyn (Dynamic (eqTypeRep (typeRep #Integer) -> Just HRefl) n) = show n
showDyn (Dynamic tr _) = show tr
That first pattern match is quite a mouthful, but after playing with a few different ways of formatting it I'm convinced that there just is no way to make that look good. You can try it in ghci:
> showDyn (toDyn ((3,4), (True, "hi")))
"DynamicPair(DynamicPair(3,4),DynamicPair(Bool,[Char]))"
I could only manage to obtain this horrible solution.
{-# LANGUAGE GADTs, ScopedTypeVariables, TypeApplications #-}
{-# OPTIONS -Wall #-}
import Type.Reflection
import Data.Dynamic
Here we define the TyCon for (,) and Int. (I'm pretty sure there must be an easier way.)
pairTyCon :: TyCon
pairTyCon = someTypeRepTyCon (someTypeRep [('a','b')])
intTyCon :: TyCon
intTyCon = someTypeRepTyCon (someTypeRep [42 :: Int])
Then we dissect the Dynamic type. First we check if it is an Int.
showDynamic :: Dynamic -> String
showDynamic x = case x of
Dynamic tr#(Con k) v | k == intTyCon ->
case eqTypeRep tr (typeRep # Int) of
Just HRefl -> show (v :: Int)
_ -> error "It really should be an int"
-- to be continued
The above is ugly, since we first pattern match against the TyCon using == instead of pattern matching, which prevents the type refinement of v into an Int. So, we still have to resort to eqTypeRep to perform a second check which we already know has to succeed.
I think it could be made pretty by checking eqTypeRep in advance, for instance. Or fromDyn. It does not matter.
What matters is that the pair case below is even more messy, and can not be made pretty in the same way, as far as I can see.
-- continuing from above
Dynamic tr#(App (App t0#(Con k :: TypeRep p)
(t1 :: TypeRep a1))
(t2 :: TypeRep a2)) v | k == pairTyCon ->
withTypeable t0 $
withTypeable t1 $
withTypeable t2 $
case ( eqTypeRep tr (typeRep #(p a1 a2))
, eqTypeRep (typeRep #p) (typeRep #(,))) of
(Just HRefl, Just HRefl) ->
"DynamicPair("
++ showDynamic (Dynamic t1 (fst v))
++ ", "
++ showDynamic (Dynamic t2 (snd v))
++ ")"
_ -> error "It really should be a pair!"
_ -> "Dynamic: not an int, not a pair"
Above we match the TypeRep so that it represents something of type p a1 a2. We require that the representation of p to be pairTyCon.
As before this does not trigger type refinement, since it is done with == instead of pattern matching. We need to perform another explicit match to force p ~ (,) and another for the final refinement v :: (a1,a2). Sigh.
Finally, we can take fst v and snd v, turn them into Dynamic once again, and pair them. Effectively, we turned the original x :: Dynamic into something like (fst x, snd x) where both components are Dynamic. Now we can recurse.
I would really like to avoid the errors, but I can not see how to do that at the moment.
The redeeming part is that the approach is very general, and can be easily adapted to other type constructors.

What does '#' mean in Haskell?

I've tried googling but come up short. I am furthering my Haskell knowledge by reading some articles and I came across one that uses a syntax I've never seen before.
An example would be:
reconstruct node#(Node a b c l r) parent#(Node b d le ri)
I've never seen these #'s before. I tried searching online for an answer but came up short. Is this simply a way to embed tags to help make things clearer, or do they have an actual impact on the code?
It is used in pattern matching. Now node variable will refer to the entire Node data type for the argument Node a b c l r. So instead of passing to the function as Node a b c l r, you can use node instead to pass it up.
A much simpler example to demonstrate it:
data SomeType = Leaf Int Int Int | Nil deriving Show
someFunction :: SomeType -> SomeType
someFunction leaf#(Leaf _ _ _) = leaf
someFunction Nil = Leaf 0 0 0
The someFunction can also be written as:
someFunction :: SomeType -> SomeType
someFunction (Leaf x y z) = Leaf x y z
someFunction Nil = Leaf 0 0 0
See how simpler was the first version ?
Using #t as a type indicator
Besides the argument pattern matching usage described in the answer of #Sibi, in Haskell the "at" character ('#', also known as an arobase character) can be used in some contexts to force a typing decision. This is mentioned in the comments by #Josh.F.
This is not part of the default language features, and is known as the Type Application Haskell language extension. In summary, the extension allows you to give explicit type arguments to a polymorphic function such as read. In a classic .hs source file, the relevant pragma must be included:
{-# LANGUAGE TypeApplications #-}
Example:
$ ghci
GHCi, version 8.2.2: http://www.haskell.org/ghc/ :? for help
λ>
λ> let x = (read #Integer "33")
<interactive>:4:10: error:
Pattern syntax in expression context: read#Integer
Did you mean to enable TypeApplications?
λ>
λ> :set -XTypeApplications
λ>
λ> let x = (read #Integer "33")
λ>
λ> :type x
x :: Integer
λ>
λ> x
33
λ>
Further details
For the read polymorphic function, the type indicator introduced by # relates to the type of the result returned by read. But this is not generally true.
Generally speaking, you have to consider the type variables that appear in the type signature of the function at hand. For example, let's have a look at the fmap library function.
fmap :: Functor ft => (a -> b) -> ft a -> ft b
So here, we have 3 type variables, in order of appearance: ft, a, b. If we specialize fmap like this:
myFmap = fmap #type1 #type2 #type3
then type1 will relate to ft, type2 will relate to a and type3 will relate to b. Also, there is a special dummy type indicator #_ which means: “here, any type goes”.
For example, we can force the output type of fmap to be Integer and the functor to be the plain list [], leaving the input type a unspecified:
λ>
λ> myFmap = fmap #[] #_ #Integer
λ>
λ> :type myFmap
myFmap :: (_ -> Integer) -> [_] -> [Integer]
λ>
As for the read function, its type is:
read :: Read a => String -> a
So there is only room for one type indicator, and it relates to the type of the result returned by read, as displayed above.

QuickCheck: How to use exhaustiveness checker to prevent forgotten constructors of a sum type

I have a Haskell data type like
data Mytype
= C1
| C2 Char
| C3 Int String
If I case on a Mytype and forget to handle one of the cases, GHC gives me a warning (exhaustiveness check).
I now want to write a QuickCheck Arbitrary instance to generate MyTypes like:
instance Arbitrary Mytype where
arbitrary = do
n <- choose (1, 3 :: Int)
case n of
1 -> C1
2 -> C2 <$> arbitrary
3 -> C3 <$> arbitrary <*> someCustomGen
The problem with this is that I can add a new alternative to Mytype and forget to update the Arbitrary instance, thus having my tests not test that alternative.
I would like to find a way of using GHC's exhaustiveness checker to remind me of forgotten cases in my Arbitrary instance.
The best I've come up with is
arbitrary = do
x <- elements [C1, C2 undefined, C3 undefined undefined]
case x of
C1 -> C1
C2 _ -> C2 <$> arbitrary
C3 _ _ -> C3 <$> arbitrary <*> someCustomGen
But it doesn't really feel elegant.
I intuitively feel that there's no 100% clean solution to this, but would appreciate anything that reduces the chance of forgetting such cases - especially in a big project where code and tests are separated.
I implemented a solution with TemplateHaskell, you can find a prototype at https://gist.github.com/nh2/d982e2ca4280a03364a8. With this you can write:
instance Arbitrary Mytype where
arbitrary = oneof $(exhaustivenessCheck ''Mytype [|
[ pure C1
, C2 <$> arbitrary
, C3 <$> arbitrary <*> arbitrary
]
|])
It works like this: You give it a type name (like ''Mytype) and an expression (in my case a list of arbitrary style Gens). It gets the list of all constructors for that type name and checks whether the expression contains all of these constructors at least once. If you just added a constructor but forgot to add it to the Arbitrary instance, this function will warn you at compile time.
This is how it's implemented with TH:
exhaustivenessCheck :: Name -> Q Exp -> Q Exp
exhaustivenessCheck tyName qList = do
tyInfo <- reify tyName
let conNames = case tyInfo of
TyConI (DataD _cxt _name _tyVarBndrs cons _derives) -> map conNameOf cons
_ -> fail "exhaustivenessCheck: Can only handle simple data declarations"
list <- qList
case list of
input#(ListE l) -> do
-- We could be more specific by searching for `ConE`s in `l`
let cons = toListOf tinplate l :: [Name]
case filter (`notElem` cons) conNames of
[] -> return input
missings -> fail $ "exhaustivenessCheck: missing case: " ++ show missings
_ -> fail "exhaustivenessCheck: argument must be a list"
I'm using GHC.Generics to easily traverse the syntax tree of the Exp: With toListOf tinplate exp :: [Name] (from lens) I can easily find all Names in the whole exp.
I was surprised that the types from Language.Haskell.TH do not have Generic instances, and neither (with current GHC 7.8) do Integer or Word8 - Generic instances for these are required because they appear in Exp. So I added them as orphan instances (for most things, StandaloneDeriving does it but for primitive types like Integer I had to copy-paste instances as Int has them).
The solution is not perfect because it doesn't use the exhaustiveness checker like case does, but as we agree, that's not possible while staying DRY, and this TH solution is DRY.
One possible improvement/alternative would be to write a TH function that does this check for all Arbitrary instances in a whole module at once instead of calling exhaustivenessCheck inside each Arbitrary instance.
You want to ensure that your code behaves in a particular way; the simplest way to check the behaviour of code is to test it.
In this case, the desired behaviour is that each constructor gets reasonable coverage in tests. We can check that with a simple test:
allCons xs = length xs > 100 ==> length constructors == 3
where constructors = nubBy eqCons xs
eqCons C1 C1 = True
eqCons C1 _ = False
eqCons (C2 _) (C2 _) = True
eqCons (C2 _) _ = False
eqCons (C3 _ _) (C3 _ _) = True
eqCons (C3 _ _) _ = False
This is pretty naive, but it's a good first shot. Its advantages:
eqCons will trigger an exhaustiveness warning if new constructors are added, which is what you want
It checks that your instance is handling all constructors, which is what you want
It also checks that all constructors are actually generated with some useful probability (in this case at least 1%)
It also checks that your instance is usable, eg. doesn't hang
Its disadvantages:
Requires a large amount of test data, in order to filter out those with length > 100
eqCons is quite verbose, since a catch-all eqCons _ _ = False would bypass the exhaustiveness check
Uses magic numbers 100 and 3
Not very generic
There are ways to improve this, eg. we can compute the constructors using the Data.Data module:
allCons xs = sufficient ==> length constructors == consCount
where sufficient = length xs > 100 * consCount
constructors = length . nub . map toConstr $ xs
consCount = dataTypeConstrs (head xs)
This loses the compile-time exhaustiveness check, but it's redundant as long as we test regularly and our code has become more generic.
If we really want the exhaustiveness check, there are a few places where we could shoe-horn it back in:
allCons xs = sufficient ==> length constructors == consCount
where sufficient = length xs > 100 * consCount
constructors = length . nub . map toConstr $ xs
consCount = length . dataTypeConstrs $ case head xs of
x#(C1) -> x
x#(C2 _) -> x
x#(C3 _ _) -> x
Notice that we use consCount to eliminate the magic 3 completely. The magic 100 (which determined the minimum required frequency of a constructor) now scales with consCount, but that just requires even more test data!
We can solve that quite easily using a newtype:
consCount = length (dataTypeConstrs C1)
newtype MyTypeList = MTL [MyType] deriving (Eq,Show)
instance Arbitrary MyTypeList where
arbitrary = MTL <$> vectorOf (100 * consCount) arbitrary
shrink (MTL xs) = MTL (shrink <$> xs)
allCons (MTL xs) = length constructors == consCount
where constructors = length . nub . map toConstr $ xs
We can put a simple exhaustiveness check in there somewhere if we like, eg.
instance Arbitrary MyTypeList where
arbitrary = do x <- arbitrary
MTL <$> vectorOf (100 * consCount) getT
where getT = do x <- arbitrary
return $ case x of
C1 -> x
C2 _ -> x
C3 _ _ -> x
shrink (MTL xs) = MTL (shrink <$> xs)
Here I exploit an unused variable _x. This is not really more elegant than your solution, though.
instance Arbitrary Mytype where
arbitrary = do
let _x = case _x of C1 -> _x ; C2 _ -> _x ; C3 _ _ -> _x
n <- choose (1, 3 :: Int)
case n of
1 -> C1
2 -> C2 <$> arbitrary
3 -> C3 <$> arbitrary <*> someCustomGen
Of course, one has to keep the last case coherent with the dummy definition of _x, so it is not completely DRY.
Alternatively, one might exploit Template Haskell to build a compile-time assert checking that the constructors in Data.Data.dataTypeOf are the expected ones. This assert has to be kept coherent with the Arbitrary instance, so this is not completely DRY either.
If you do not need custom generators, I believe Data.Data can be exploited to generate Arbitrary instances via Template Haskell (I think I saw some code doing exactly that, but I can't remember where). In this way, there's no chance the instance can miss a constructor.
Here is a solution using the generic-random library:
{-# language DeriveGeneric #-}
{-# language TypeOperators #-}
import Generic.Random
import GHC.Generics
import Test.QuickCheck
data Mytype
= C1
| C2 Char
| C3 Int String
deriving Generic
instance Arbitrary Mytype where
arbitrary = genericArbitraryG customGens uniform
where
customGens :: Gen String :+ ()
customGens = someCustomGen :+ ()
someCustomGen :: Gen String
someCustomGen = undefined
genericArbitraryG takes care of generating each constructor of MyType. In this case we use uniform to get a uniform distribution of constructors. With customGens we define that each String field in Mytype is generated with someCustomGen.
See Generic.Random.Tutorial for more examples.

Convert nested lists to custom data type

I am trying to convert nested lists into a custom type called Mydata using a list comprehension as follows:
main = do
let a = [["12.345", "1", "4.222111"],
["31.2", "12", "9.1234"],
["43.111111", "3", "8.13"],
["156.112121", "19", "99.99999"]]
let b = foo a
print b
foo xss = [(xs,xs) | xs <- xss, xs <- xss]
where
xs = Mydata (read xs!!0 :: Float) (read xs!!1 :: Int) (read xs!!2 :: Float)
data Mydata = Mydata {valA :: Float, valB :: Int, valC :: Float}
When I run my program I get the following error:
1.hs:11:28:
Couldn't match expected type `String' with actual type `Mydata'
In the first argument of `read', namely `xs'
In the first argument of `(!!)', namely `read xs'
In the first argument of `Mydata', namely `(read xs !! 0 :: Float)'
Can anyone help me figure out what the problem is? Thanks.
xs definition in list comprehension is (perhaps unintentionally) recursive, and makes no sense. Possible implementation follows:
data Mydata = Mydata {valA :: Float, valB :: Int, valC :: Float} deriving Show
-- rely on type inference instead of specifying explicit type for each `read'
dataFromList [a, b, c] = Mydata (read a) (read b) (read c)
dataFromList _ = error "dataFromList: not enough arguments in list"
main = do
let a = [["12.345", "1", "4.222111"],
["31.2", "12", "9.1234"],
["43.111111", "3", "8.13"],
["156.112121", "19", "99.99999"]]
let b = map dataFromList a
-- alternatively
-- let b = [dataFromList triple | triple <- a]
print b
{-
I'm going to take the opportunity to tell you some other things I think will help in the long run as well as fix the problem.
-}
import Control.Applicative
import Data.Maybe
import Network.CGI.Protocol (maybeRead)
{-
The Control.Applicative lets me use <$> and <*> which are really handy functions for working with loads of things (more later).
I'm going to use maybeRead later. I don't know why it's not in Data.Maybe.
Data structure first. I've derived show so we can print Mydata.
-}
data Mydata = Mydata {valA :: Float,
valB :: Int,
valC :: Float}
deriving Show
{-
I've put somedata as a definition in the main body (you had let a = inside main), because I felt you were seriously overusing the IO monad.
It's worth trying to do as much as possible in pure world, because it makes debugging much easier.
Maybe in your actual problem, you'll have read somedata in from somewhere, but for writing the functions,
having a bit of test data like this lying around is a big bonus. (Try though to only mention somedata as a definition
here once, so you don't get a rash of global constants!)
-}
somedata = [["12.345", "1", "4.222111"],
["31.2", "12", "9.1234"],
["43.111111", "3", "8.13"],
["156.112121", "19", "99.99999"]]
somewrong = [ ["1", "2", "3" ], -- OK
["1.0", "2", "3.0" ], -- OK, same value as first one
["1", "2.0", "3" ], -- wrong, decimal for valB
["", "two", "3.3.3"] ] -- wrong, wrong, wrong.
{-
Let's write a function to read a single Mydata, but use Maybe Mydata so we can recover gracefully if it doesn't work out.
maybeRead :: Read a => String -> Maybe a, so it turns strings into Just what you want, or gives you Nothing if it can't.
This is better than simply crashing with an error message.
(Better still would be to return Either an error message explaining the problem or the Right answer, but I'm going to skip that for today.)
I'm going to write this three ways, getting nicer and nicer.
-}
readMydata_v1 :: [String] -> Maybe Mydata
readMydata_v1 [as, bs, cs] = case (maybeRead as, maybeRead bs, maybeRead cs) of
(Just a, Just b, Just c) -> Just $ Mydata a b c
_ -> Nothing
readMydata_v1 _ = Nothing -- anything else is the wrong number of Strings
{-
so we look at (maybeRead as, maybeRead bs, maybeRead cs) and if they all worked, we make a Mydata out of them, then return Just the right answer,
but if something else happened, one of them was a Nothing, so we can't make a Mydata, and so we get Nothing overall.
Try it out in gchi with map readMydata_v1 somedata and map readMydata_v1 somewrong.
Notice how because I used the expression Mydata a b c, it forces the types of a, b and c to be Float, Int and Float in the (Just a, Just b, Just c) pattern.
That pattern is the output of (maybeRead as, maybeRead bs, maybeRead cs), which forces the types of the three uses of maybeRead to be right -
I don't need to give individual type signatures. Type signatures are really handy, but they're not pretty in the middle of a function.
Now I like using Maybe, but I don't like writing loads of case statements inside each other, so I could use the face that Maybe is a Monad.
See Learn You a Haskell for Great Good http://learnyouahaskell.com for more details about monads, but for my purposes here, it's like I can treat a Maybe value like it's IO even though it's not.
-}
readMydata_v2 :: [String] -> Maybe Mydata
readMydata_v2 [as,bs,cs] = do
a <- maybeRead as
b <- maybeRead bs
c <- maybeRead cs
return $ Mydata a b c
readMydata_v2 _ = Nothing -- anything else is the wrong number of Strings
{-
I seem to write no error handling code! Aren't Maybe monads great!
Here we take whatever a we can get out of maybeRead as, whatever b we can get from reading bs
and whatever c we get from cs, and if that has all worked we get Just $ Mydata a b c.
The Maybe monad deals with any Nothings we get by stopping and returning Nothing, and wraps any correct answer in Just.
Whilst this is really nice, it doesn't feel very functional programming, so let's go the whole hog and make it Applicative.
You should read about Applicative in http://learnyouahaskell.com, but for now, lets just use it.
Whenever you find yourself writing
foo x y z = do
thing1 <- something x
thing2 <- somethingelse y
thing3 <- anotherthing x z
thing4 <- yetmore y y z
return $ somefunction thing1 thing2 thing3 thing4
it means you're using a monad when you could more cleanly use an "applicative functor".
All this means in practice is that you could have written that
foo x y z = somefunction <$> something x <*> somethingelse y <*> anotherthing x z <*> yetmore y y z
or if you prefer,
foo x y z = somefunction <$> something x
<*> somethingelse y
<*> anotherthing x z
<*> yetmore y y z
this is nicer because (a) it feels more like ordinary function application (notice that <$> works like $ and <*> works like a space ) and (b) you don't need
to invent names thing1 etc.
It means find out the results of something x and somethingelse y and anotherthing x z and yetmore y y z then apply somefunction to the result.
Let's do readMydata the applicative way:
-}
readMydata_nice :: [String] -> Maybe Mydata
readMydata_nice [a,b,c] = Mydata <$> maybeRead a <*> maybeRead b <*> maybeRead c
readMydata_nice _ = Nothing
{-
Aaaahhhhh, so clean, so functional, so easy. Mmmmm. :) Think more, write less.
This means take the resuts of maybeRead a and maybeRead b and maybeRead c and apply Mydata to the result, but because everything is Maybe, if anything along the way is Nothing, the answer will be Nothing.
Again, you can test this out in ghci with map readMydata_nice somedata or map readMydata_nice somewrong
Anyway, lets write main, which is now more functional too.
-}
main = mapM_ print $ catMaybes $ map readMydata_nice somedata
{-
This takes each list of Strings in somedata and reads them as Maybe Mydata, then throws away the Nothings and turns them into IO print commands and does them one after another.
mapM_ works a bit like map but does every IO it creates. Because it's several prints, each one goes on a seperate line, which is much easier to read.
Here I've decided to use catMaybes to ignore the Nothing values and just print the ones that worked. In a real program,
I'd use Either like I said, so that I can pass an error message instead of silently ignoring wrong data. All the tricks we used on Maybe also work on Either.
-}
In the definition
where
xs = Mydata (read xs!!0 :: Float) (read xs!!1 :: Int) (read xs!!2 :: Float)
you are using xs on the left and the right-hand side of the definition. Therefore, it has to have the same type on both sides. The compiler assumes that the type of xs is MyData and you cannot apply read to a value of that type.

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

Resources