Convert nested lists to custom data type - haskell

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.

Related

Best way to apply arguments of mixed, possibly Applicative, types to a function

I'm fairly new to Haskell and functional programming and I have recently been learning about Functors, Applicatives and Monads. While I seem to understand the basics, I have trouble figuring out the best/most idiomatic way apply function arguments when the type of some arguments changes to an Applicative. Consider the following, simple code:
myfun :: Int -> Int -> Int -> Int
myfun a b c = a + b + c -- lets pretend this does something more complicated
a = 5
b = 10
c = 20
result = myfun a b c
Using myfun to calculate the result is fairly straightforward. However, as our requirements change, our inputs a, b and c may change to be i.e. Maybe Int or [Int] rather then Int. We can still use our unmodified myfun by doing one of the following:
result = myfun <$> a <*> b <*> c -- either like this
result = liftA3 myfun a b c -- or like that
However, in practice the arguments a, b and c may not always end up to be inside the same Applicative, and thus the two methods mentioned above would not work. What is the best way to still make the myfun function work without modifying it? Consider the following scenarios for a, b and c:
Some are Int, some are Maybe Int (result of the application would be Maybe Int)
Some are Maybe Int, some are Either String Int (result could be Maybe Int or Either String Int, with the semantics of short-circuiting the calculation if any argument is Nothing or Left)
Some are [Int], some are Maybe Int (result should be Maybe [Int], with the semantics of calculating all possible combinations as if all arguments were [Int], then wrapping that inside a Just, unless on of the Maybies are Nothing, in which case we short-circuit to Nothing)
Any insights are very much appreciated!
It depends on what you want to happen. There may not be any universal way to combine different monads. In general, you can often (always?) use a monad transformer when you truly need to combine different monads, but usually there are simpler solutions. That's the case with the specific combinations you mention.
In all of these specific cases, you can transform one of the monads into another. In the following, I'll give some examples of ways this could be done.
Some of these examples use functions from Data.Maybe, so I'll start with:
import Data.Maybe
It's not required in the first example, but will be in the second and third.
Some Int, some Maybe Int
If you have a combination of Int and Maybe Int values, the solution is straightforward. Just elevate the Int values to Maybe Int. You can use Just or pure for this. Here's an example using pure:
a1 = 5
b1 = Just 10
c1 = 20
result1 :: Maybe Int
result1 = myfun <$> pure a1 <*> b1 <*> pure c1
The result is Just 35.
Some Maybe Int, some Either String Int
You can repeat the trick with transforming one of the monads into the other. You can transform Maybe Int values to Either String Int values if you have a good String to use for Nothing cases. You can also transform Either String Int values to Maybe Int values by throwing away the String values.
Here's an example that transforms Maybe Int to Either String Int:
a2 = Just 5
b2 = Right 10
c2 = Left "Boo!"
result2 :: Either String Int
result2 = myfun <$> maybe (Left "No value") Right a2 <*> b2 <*> c2
This combination uses the maybe function from Data.Maybe. The result is Left "Boo!".
Some [Int], some Maybe Int
You can easily turn Maybe Int into [Int] using maybeToList:
a3 = [5, 10]
b3 = Nothing
c3 = Just 20
result3 :: [Int]
result3 = myfun <$> a3 <*> maybeToList b3 <*> maybeToList c3
The result of doing this is [] because Nothing transforms to [], and that's how Applicative works for lists. This may not be what you want, but I hope these examples can inspire you to come up with the compositions you'd like.
As mentioned in other answers, here perhaps it doesn't make much sense to preserve the distinctions between the Applictatives, it would be better to reduce them to a single one before applying them to myfun.
But sometimes it is convenient to preserve the distinctions. The good news is that Applicatives compose, meaning that the "nesting" of two or more Applicatives can always be given an Applicative instance.
For example, we could define a combined Applicative like this:
{-# LANGUAGE DerivingVia, TypeOperators #-}
import Data.Functor.Compose
newtype A a = A (Either String (Maybe [a]))
deriving (Functor,Applicative)
via Either String `Compose` Maybe `Compose` []
We are using -XDerivingVia in our own auxiliary datatype to avoid having to work with nested Compose newtypes, which would be a bit more cumbersome.
Applicative composition works "from the outer layer inwards". That is, if there's a Left somehwere, all the computation ends with a Left. If the outer layer succeeds, then we combine the inner Maybes, and if they all turn to be Just, we applicatively combine the inner lists.
We also need some tedious boilerplate: injection functions into our combined Applicative:
liftL1 :: Either String a -> A a
liftL1 = A . fmap (pure . pure)
liftL2 :: Maybe a -> A a
liftL2 = A . pure . fmap pure
liftL3 :: [a] -> A a
liftL3 = A . pure . pure
Putting it to work:
a = Right 5
b = Just 10
c = [20]
result = liftA3 myfun (liftL1 a) (liftL2 b) (liftL3 c)
Or, using -XApplicativeDo:
result = do
a <- liftL1 $ Right 5
b <- liftL2 $ Just 10
c <- liftL3 $ [20]
pure $ myfun a b c

Haskell's (<-) in Terms of the Natural Transformations of Monad

So I'm playing around with the hasbolt module in GHCi and I had a curiosity about some desugaring. I've been connecting to a Neo4j database by creating a pipe as follows
ghci> pipe <- connect $ def {credentials}
and that works just fine. However, I'm wondering what the type of the (<-) operator is (GHCi won't tell me). Most desugaring explanations describe that
do x <- a
return x
desugars to
a >>= (\x -> return x)
but what about just the line x <- a?
It doesn't help me to add in the return because I want pipe :: Pipe not pipe :: Control.Monad.IO.Class.MonadIO m => m Pipe, but (>>=) :: Monad m => m a -> (a -> m b) -> m b so trying to desugar using bind and return/pure doesn't work without it.
Ideally it seems like it'd be best to just make a Comonad instance to enable using extract :: Monad m => m a -> a as pipe = extract $ connect $ def {creds} but it bugs me that I don't understand (<-).
Another oddity is that, treating (<-) as haskell function, it's first argument is an out-of-scope variable, but that wouldn't mean that
(<-) :: a -> m b -> b
because not just anything can be used as a free variable. For instance, you couldn't bind the pipe to a Num type or a Bool. The variable has to be a "String"ish thing, except it never is actually a String; and you definitely can't try actually binding to a String. So it seems as if it isn't a haskell function in the usual sense (unless there is a class of functions that take values from the free variable namespace... unlikely). So what is (<-) exactly? Can it be replaced entirely by using extract? Is that the best way to desugar/circumvent it?
I'm wondering what the type of the (<-) operator is ...
<- doesn't have a type, it's part of the syntax of do notation, which as you know is converted to sequences of >>= and return during a process called desugaring.
but what about just the line x <- a ...?
That's a syntax error in normal haskell code and the compiler would complain. The reason the line:
ghci> pipe <- connect $ def {credentials}
works in ghci is that the repl is a sort of do block; you can think of each entry as a line in your main function (it's a bit more hairy than that, but that's a good approximation). That's why you need (until recently) to say let foo = bar in ghci to declare a binding as well.
Ideally it seems like it'd be best to just make a Comonad instance to enable using extract :: Monad m => m a -> a as pipe = extract $ connect $ def {creds} but it bugs me that I don't understand (<-).
Comonad has nothing to do with Monads. In fact, most Monads don't have any valid Comonad instance. Consider the [] Monad:
instance Monad [a] where
return x = [x]
xs >>= f = concat (map f xs)
If we try to write a Comonad instance, we can't define extract :: m a -> a
instance Comonad [a] where
extract (x:_) = x
extract [] = ???
This tells us something interesting about Monads, namely that we can't write a general function with the type Monad m => m a -> a. In other words, we can't "extract" a value from a Monad without additional knowledge about it.
So how does the do-notation syntax do {x <- [1,2,3]; return [x,x]} work?
Since <- is actually just syntax sugar, just like how [1,2,3] actually means 1 : 2 : 3 : [], the above expression actually means [1,2,3] >>= (\x -> return [x,x]), which in turn evaluates to concat (map (\x -> [[x,x]]) [1,2,3])), which comes out to [1,1,2,2,3,3].
Notice how the arrow transformed into a >>= and a lambda. This uses only built-in (in the typeclass) Monad functions, so it works for any Monad in general.
We can pretend to extract a value by using (>>=) :: Monad m => m a -> (a -> m b) -> m b and working with the "extracted" a inside the function we provide, like in the lambda in the list example above. However, it is impossible to actually get a value out of a Monad in a generic way, which is why the return type of >>= is m b (in the Monad)
So what is (<-) exactly? Can it be replaced entirely by using extract? Is that the best way to desugar/circumvent it?
Note that the do-block <- and extract mean very different things even for types that have both Monad and Comonad instances. For instance, consider non-empty lists. They have instances of both Monad (which is very much like the usual one for lists) and Comonad (with extend/=>> applying a function to all suffixes of the list). If we write a do-block such as...
import qualified Data.List.NonEmpty as N
import Data.List.NonEmpty (NonEmpty(..))
import Data.Function ((&))
alternating :: NonEmpty Integer
alternating = do
x <- N.fromList [1..6]
-x :| [x]
... the x in x <- N.fromList [1..6] stands for the elements of the non-empty list; however, this x must be used to build a new list (or, more generally, to set up a new monadic computation). That, as others have explained, reflects how do-notation is desugared. It becomes easier to see if we make the desugared code look like the original one:
alternating :: NonEmpty Integer
alternating =
N.fromList [1..6] >>= \x ->
-x :| [x]
GHCi> alternating
-1 :| [1,-2,2,-3,3,-4,4,-5,5,-6,6]
The lines below x <- N.fromList [1..6] in the do-block amount to the body of a lambda. x <- in isolation is therefore akin to a lambda without body, which is not a meaningful thing.
Another important thing to note is that x in the do-block above does not correspond to any one single Integer, but rather to all Integers in the list. That already gives away that <- does not correspond to an extraction function. (With other monads, the x might even correspond to no values at all, as in x <- Nothing or x <- []. See also Lazersmoke's answer.)
On the other hand, extract does extract a single value, with no ifs or buts...
GHCi> extract (N.fromList [1..6])
1
... however, it is really a single value: the tail of the list is discarded. If we want to use the suffixes of the list, we need extend/(=>>)...
GHCi> N.fromList [1..6] =>> product =>> sum
1956 :| [1236,516,156,36,6]
If we had a co-do-notation for comonads (cf. this package and the links therein), the example above might get rewritten as something in the vein of:
-- codo introduces a function: x & f = f x
N.fromList [1..6] & codo xs -> do
ys <- product xs
sum ys
The statements would correspond to plain values; the bound variables (xs and ys), to comonadic values (in this case, to list suffixes). That is exactly the opposite of what we have with monadic do-blocks. All in all, as far as your question is concerned, switching to comonads just swaps which things we can't refer to outside of the context of a computation.

What is the intuitive meaning of "join"?

What is the intuitive meaning of join for a Monad?
The monads-as-containers analogies make sense to me, and inside these analogies join makes sense. A value is double-wrapped and we unwrap one layer. But as we all know, a monad is not a container.
How might one write sensible, understandable code using join in normal circumstances, say when in IO?
An action :: IO (IO a) is a way of producing a way of producing an a. join action, then, is a way of producing an a by running the outermost producer of action, taking the producer it produced and then running that as well, to finally get to that juicy a.
join collapses consecutive layers of the type constructor.
A valid join must satisfy the property that, for any number of consecutive applications of the type constructor, it shouldn't matter the order in which we collapse the layers.
For example
ghci> let lolol = [[['a'],['b','c']],[['d'],['e']]]
ghci> lolol :: [[[Char]]]
ghci> lolol :: [] ([] ([] Char)) -- the type can also be expressed like this
ghci> join (fmap join lolol) -- collapse inner layers first
"abcde"
ghci> join (join lolol) -- collapse outer layers first
"abcde"
(We used fmap to "get inside" the outer monadic layer so that we could collapse the inner layers first.)
A small non container example where join is useful: for the function monad (->) a, join is equivalent to \f x -> f x x, a function of type (a -> a -> b) -> a -> b that applies two times the same argument to another function.
For the List monad, join is simply concat, and concatMap is join . fmap.
So join implicitly appears in any list expression which uses concat
or concatMap.
Suppose you were asked to find all of the numbers which are divisors of any
number in an input list. If you have a divisors function:
divisors :: Int -> [Int]
divisors n = [ d | d <- [1..n], mod n d == 0 ]
you might solve the problem like this:
foo xs = concat $ (map divisors xs)
Here we are thinking of solving the problem by first mapping the
divisors function over all of the input elements and then concatenating
all of the resulting lists. You might even think that this is a very
"functional" way of solving the problem.
Another approch would be to write a list comprehension:
bar xs = [ d | x <- xs, d <- divisors x ]
or using do-notation:
bar xs = do x <- xs
d <- divisors
return d
Here it might be said we're thinking a little more
imperatively - first draw a number from the list xs; then draw
a divisors from the divisors of the number and yield it.
It turns out, though, that foo and bar are exactly the same function.
Morever, these two approaches are exactly the same in any monad.
That is, for any monad, and appropriate monadic functions f and g:
do x <- f
y <- g x is the same as: (join . fmap g) f
return y
For instance, in the IO monad if we set f = getLine and g = readFile,
we have:
do x <- getLine
y <- readFile x is the same as: (join . fmap readFile) getLine
return y
The do-block is a more imperative way of expressing the action: first read a
line of input; then treat returned string as a file name, read the contents
of the file and finally return the result.
The equivalent join expression seems a little unnatural in the IO-monad.
However it shouldn't be as we are using it in exactly the same way as we
used concatMap in the first example.
Given an action that produces another action, run the action and then run the action that it produces.
If you imagine some kind of Parser x monad that parses an x, then Parser (Parser x) is a parser that does some parsing, and then returns another parser. So join would flatten this into a Parser x that just runs both actions and returns the final x.
Why would you even have a Parser (Parser x) in the first place? Basically, because fmap. If you have a parser, you can fmap a function that changes the result over it. But if you fmap a function that itself returns a parser, you end up with a Parser (Parser x), where you probably want to just run both actions. join implements "just run both actions".
I like the parsing example because a parser typically has a runParser function. And it's clear that a Parser Int is not an integer. It's something that can parse an integer, after you give it some input to parse from. I think a lot of people end up thinking of an IO Int as being just a normal integer but with this annoying IO bit that you can't get rid of. It isn't. It's an unexecuted I/O operation. There's no integer "inside" it; the integer doesn't exist until you actually perform the I/O.
I find these things easier to interpret by writing out the types and refactoring them a bit to reveal what the functions do.
Reader monad
The Reader type is defined thus, and its join function has the type shown:
newtype Reader r a = Reader { runReader :: r -> a }
join :: Reader r (Reader r a) -> Reader r a
Since this is a newtype, this means that the type Reader r a is isomorphic to r -> a. So we can refactor the type definition to give us this type that, albeit it's not the same, it's really "the same" with scare quotes:
In the (->) r monad, which is isomorphic to Reader r, join is the function:
join :: (r -> r -> a) -> r -> a
So the Reader join is the function that takes a two-place function (r -> r -> a) and applies to the same value at both its argument positions.
Writer monad
Since the Writer type has this definition:
newtype Writer w a = Writer { runWriter :: (a, w) }
...then when we remove the newtype, its join function has a type isomorphic to:
join :: Monoid w => ((a, w), w) -> (a, w)
The Monoid constraint needs to be there because the Monad instance for Writer requires it, and it lets us guess right away what the function does:
join ((a, w0), w1) = (a, w0 <> w1)
State monad
Similarly, since State has this definition:
newtype State s a = State { runState :: s -> (a, s) }
...then its join is like this:
join :: (s -> (s -> (a, s), s)) -> s -> (a, s)
...and you can also venture just writing it directly:
join f s0 = (a, s2)
where
(g, s1) = f s0
(a, s2) = g s1
{- Here's the "map" to the variable names in the function:
f g s2 s1 s0 s2
join :: (s -> (s -> (a, s ), s )) -> s -> (a, s )
-}
If you stare at this type a bit, you might think that it bears some resemblance to both the Reader and Writer's types for their join operations. And you'd be right! The Reader, Writer and State monads are all instances of a more general pattern called update monads.
List monad
join :: [[a]] -> [a]
As other people have pointed out, this is the type of the concat function.
Parsing monads
Here comes a really neat thing to realize. Very often, "fancy" monads turn out to be combinations or variants of "basic" ones like Reader, Writer, State or lists. So often what I do when confronted with a novel monad is ask: which of the basic monads does it resemble, and how?
Take for example parsing monads, which have been brought up in other answers here. A simplistic parser monad (with no support for important things like error reporting) looks like this:
newtype Parser a = Parser { runParser :: String -> [(a, String)] }
A Parser is a function that takes a string as input, and returns a list of candidate parses, where each candidate parse is a pair of:
A parse result of type a;
The leftovers (the suffix of the input string that was not consumed in that parse).
But notice that this type looks very much like the state monad:
newtype Parser a = Parser { runParser :: String -> [(a, String)] }
newtype State s a = State { runState :: s -> (a, s) }
And this is no accident! Parser monads are nondeterministic state monads, where the state is the unconsumed portion of the input string, and parse steps generate alternatives that may be later rejected in light of further input. List monads are often called "nondeterminism" monads, so it's no surprise that a parser resembles a mix of the state and list monads.
And this intuition can be systematized by using monad transfomers. The state monad transformer is defined like this:
newtype StateT s m a = StateT { runStateT :: s -> m (a, s) }
Which means that the Parser type from above can be written like this as well:
type Parser a = StateT String [] a
...and its Monad instance follows mechanically from those of StateT and [].
The IO monad
Imagine we could enumerate all of the possible primitive IO actions, somewhat like this:
{-# LANGUAGE GADTs #-}
data Command a where
-- An action that writes a char to stdout
putChar :: Char -> Command ()
-- An action that reads a char from stdin
getChar :: Command Char
-- ...
Then we could think of the IO type as this (which I've adapted from the highly-recommended Operational monad tutorial):
data IO a where
-- An `IO` action that just returns a constant value.
Return :: a -> IO a
-- An action that binds the result of a `Command` to
-- a function that computes the next step after it.
Bind :: Command x -> (x -> IO a) -> IO a
instance Monad IO where ...
Then join action would then look like this:
join :: IO (IO a) -> IO a
-- If the action is just `Return`, then its payload already
-- is what we need to return.
join (Return ioa) = ioa
-- If the action is a `Bind`, then its "next step" function
-- `f` produces `IO (IO a)`, so we can just recursively stick
-- a `join` to its result end.
join (Bind cmd f) = Bind cmd (join . f)
So all that the join does here is "chase down" the IO action until it sees a result that fits the pattern Return (ma :: IO a), and strip out the outer Return.
So what did I do here? Just like for parser monads, I just defined (or rather copied) a toy model of the IO type that has the virtue of being transparent. Then I work out the behavior of join from the toy model.

List comprehension and converting string to object

I have a string, like 2.7+i*3.4. I want to parse this string and get Complex number object. I try to do this:
newtype MyComplexNumber = MyComplexNumber (Complex Float)
myReadsCmplx s = [(MyComplexNumber (a :+ b)) |
(a, '+':r1) <- reads s :: [(Float, String)],
(i, '*':r2) <- reads r1 :: [(String, String)],
(b, r3) <- reads r2 :: [(Float, String)]]
But I have empty list:
*Main Data.Complex> myReadsCmplx "2.7+i*3.4"
[]
*Main Data.Complex>
You seem to be using reads as though it were a full monadic parser. It's not. It comes up with a match or none, and if the match it finds does not match your pattern, you get nada. You will be much better off using something like parsec, attoparsec, or even something super-simple like regex-applicative.

Haskell data serialization of some data implementing a common type class

Let's start with the following
data A = A String deriving Show
data B = B String deriving Show
class X a where
spooge :: a -> Q
[ Some implementations of X for A and B ]
Now let's say we have custom implementations of show and read, named show' and read' respectively which utilize Show as a serialization mechanism. I want show' and read' to have types
show' :: X a => a -> String
read' :: X a => String -> a
So I can do things like
f :: String -> [Q]
f d = map (\x -> spooge $ read' x) d
Where data could have been
[show' (A "foo"), show' (B "bar")]
In summary, I wanna serialize stuff of various types which share a common typeclass so I can call their separate implementations on the deserialized stuff automatically.
Now, I realize you could write some template haskell which would generate a wrapper type, like
data XWrap = AWrap A | BWrap B deriving (Show)
and serialize the wrapped type which would guarantee that the type info would be stored with it, and that we'd be able to get ourselves back at least an XWrap... but is there a better way using haskell ninja-ery?
EDIT
Okay I need to be more application specific. This is an API. Users will define their As, and Bs and fs as they see fit. I don't ever want them hacking through the rest of the code updating their XWraps, or switches or anything. The most i'm willing to compromise is one list somewhere of all the A, B, etc. in some format. Why?
Here's the application. A is "Download a file from an FTP server." B is "convert from flac to mp3". A contains username, password, port, etc. information. B contains file path information. There could be MANY As and Bs. Hundreds. As many as people are willing to compile into the program. Two was just an example. A and B are Xs, and Xs shall be called "Tickets." Q is IO (). Spooge is runTicket. I want to read the tickets off into their relevant data types and then write generic code that will runTicket on the stuff read' from the stuff on disk. At some point I have to jam type information into the serialized data.
I'd first like to stress for all our happy listeners out there that XWrap is a very good way, and a lot of the time you can write one yourself faster than writing it using Template Haskell.
You say you can get back "at least an XWrap", as if that meant you couldn't recover the types A and B from XWrap or you couldn't use your typeclass on them. Not true! You can even define
separateAB :: [XWrap] -> ([A],[B])
If you didn't want them mixed together, you should serialise them seperately!
This is nicer than haskell ninja-ery; maybe you don't need to handle arbitrary instances, maybe just the ones you made.
Do you really need your original types back? If you feel like using existential types because you just want to spooge your deserialised data, why not either serialise the Q itself, or have some intermediate data type PoisedToSpooge that you serialise, which can deserialise to give you all the data you need for a really good spooging. Why not make it an instance of X too?
You could add a method to your X class that converts to PoisedToSpooge.
You could call it something fun like toPoisedToSpooge, which trips nicely off the tongue, don't you think? :)
Anyway this would remove your typesystem complexity at the same time as resolving the annoying ambiguous type in
f d = map (\x -> spooge $ read' x) d -- oops, the type of read' x depends on the String
You can replace read' with
stringToPoisedToSpoogeToDeserialise :: String -> PoisedToSpooge -- use to deserialise
and define
f d = map (\x -> spooge $ stringToPoisedToSpoogeToDeserialise x) -- no ambiguous type
which we could of course write more succincly as
f = map (spooge.stringToPoisedToSpoogeToDeserialise)
although I recognise the irony here in suggesting making your code more succinct. :)
If what you really want is a heterogeneous list then use existential types. If you want serialization then use Cereal + ByteString. If you want dynamic typing, which is what I think your actual goal is, then use Data.Dynamic. If none of this is what you want, or you want me to expand please press the pound key.
Based on your edit, I don't see any reason a list of thunks won't work. In what way does IO () fail to represent both the operations of "Download a file from an FTP server" and "convert from flac to MP3"?
I'll assume you want to do more things with deserialised Tickets
than run them, because if not you may as well ask the user to supply a bunch of String -> IO()
or similar, nothing clever needed at all.
If so, hooray! It's not often I feel it's appropriate to recommend advanced language features like this.
class Ticketable a where
show' :: a -> String
read' :: String -> Maybe a
runTicket :: a -> IO ()
-- other useful things to do with tickets
This all hinges on the type of read'. read' :: Ticket a => String -> a isn't very useful,
because the only thing it can do with invalid data is crash.
If we change the type to read' :: Ticket a => String -> Maybe a this can allow us to read from disk and
try all the possibilities or fail altogether.
(Alternatively you could use a parser: parse :: Ticket a => String -> Maybe (a,String).)
Let's use a GADT to give us ExistentialQuantification without the syntax and with nicer error messages:
{-# LANGUAGE GADTs #-}
data Ticket where
MkTicket :: Ticketable a => a -> Ticket
showT :: Ticket -> String
showT (MkTicket a) = show' a
runT :: Ticket -> IO()
runT (MkTicket a) = runTicket a
Notice how the MkTicket contstuctor supplies the context Ticketable a for free! GADTs are great.
It would be nice to make Ticket and instance of Ticketable, but that won't work, because there would be
an ambiguous type a hidden in it. Let's take functions that read Ticketable types and make them read
Tickets.
ticketize :: Ticketable a => (String -> Maybe a) -> (String -> Maybe Ticket)
ticketize = ((.).fmap) MkTicket -- a little pointfree fun
You could use some unusual sentinel string such as
"\n-+-+-+-+-+-Ticket-+-+-+-Border-+-+-+-+-+-+-+-\n" to separate your serialised data or better, use separate files
altogether. For this example, I'll just use "\n" as the separator.
readTickets :: [String -> Maybe Ticket] -> String -> [Maybe Ticket]
readTickets readers xs = map (foldr orelse (const Nothing) readers) (lines xs)
orelse :: (a -> Maybe b) -> (a -> Maybe b) -> (a -> Maybe b)
(f `orelse` g) x = case f x of
Nothing -> g x
just_y -> just_y
Now let's get rid of the Justs and ignore the Nothings:
runAll :: [String -> Maybe Ticket] -> String -> IO ()
runAll ps xs = mapM_ runT . catMaybes $ readTickets ps xs
Let's make a trivial ticket that just prints the contents of some directory
newtype Dir = Dir {unDir :: FilePath} deriving Show
readDir xs = let (front,back) = splitAt 4 xs in
if front == "dir:" then Just $ Dir back else Nothing
instance Ticketable Dir where
show' (Dir p) = "dir:"++show p
read' = readDir
runTicket (Dir p) = doesDirectoryExist p >>= flip when
(getDirectoryContents >=> mapM_ putStrLn $ p)
and an even more trivial ticket
data HelloWorld = HelloWorld deriving Show
readHW "HelloWorld" = Just HelloWorld
readHW _ = Nothing
instance Ticketable HelloWorld where
show' HelloWorld = "HelloWorld"
read' = readHW
runTicket HelloWorld = putStrLn "Hello World!"
and then put it all together:
myreaders = [ticketize readDir,ticketize readHW]
main = runAll myreaders $ unlines ["HelloWorld",".","HelloWorld","..",",HelloWorld"]
Just use Either. Your users don't even have to wrap it themselves. You have your deserializer wrap it in the Either for you. I don't know exactly what your serialization protocol is, but I assume that you have some way to detect which kind of request, and the following example assumes the first byte distinguishes the two requests:
deserializeRequest :: IO (Either A B)
deserializeRequest = do
byte <- get1stByte
case byte of
0 -> do
...
return $ Left $ A <A's fields>
1 -> do
...
return $ Right $ B <B's fields>
Then you don't even need to type-class spooge. Just make it a function of Either A B:
spooge :: Either A B -> Q

Resources