Monad of list in Haskell - list

I'm trying to make this an instance of Monad in Haskell:
data Parser a = Done ([a], String) | Fail String
Now I try this code to make it an instance of Monad:
instance Functor Parser where
fmap = liftM
instance Applicative Parser where
pure = return
(<*>) = ap
instance Monad Parser where
return xs = Done ([], xs)
Done (xs, s) >>= f = Done (concat (map f xs)), s)
But this obviously doesn't work, because the function f in the bind-function is of the type a -> M b. So the (map f xs) function yields a list of M b-things. It should actually make a list of b's. How can I do this in Haskell?
NOTE: The actual error given by GHC 7.10.3 is:
SuperInterpreter.hs:71:27:
Couldn't match expected type `String' with actual type `a'
`a' is a rigid type variable bound by
the type signature for return :: a -> Parser a
at SuperInterpreter.hs:71:5
Relevant bindings include
xs :: a (bound at SuperInterpreter.hs:71:12)
return :: a -> Parser a (bound at SuperInterpreter.hs:71:5)
In the expression: xs
In the first argument of `Done', namely `([], xs)'
SuperInterpreter.hs:72:45:
Couldn't match type `Parser b' with `[b]'
Expected type: a -> [b]
Actual type: a -> Parser b
Relevant bindings include
f :: a -> Parser b (bound at SuperInterpreter.hs:72:22)
(>>=) :: Parser a -> (a -> Parser b) -> Parser b
(bound at SuperInterpreter.hs:72:5)
In the first argument of `map', namely `f'
In the first argument of `concat', namely `(map f xs)'
Failed, modules loaded: none.

leftaroundabout already showed you some of the problems.
Usually I expect a parser to be some kind of function that takes an input-String, maybe consuming some of this string and then returning an result together with the unconsumed input.
Based on this idea you can extent your code to do just this:
data ParserResult a
= Done (a, String)
| Fail String
deriving Show
data Parser a = Parser { run :: String -> ParserResult a }
instance Functor Parser where
fmap = liftM
instance Applicative Parser where
pure = return
(<*>) = ap
instance Monad Parser where
return a = Parser $ \ xs -> Done (a, xs)
p >>= f = Parser $ \ xs ->
case run p xs of
Done (a, xs') -> run (f a) xs'
Fail msg -> Fail msg
a simple example
here is a simple parser that would accept any character:
parseAnyChar :: Parser Char
parseAnyChar = Parser f
where f (c:xs) = Done (c, xs)
f "" = Fail "nothing to parse"
and this is how you would use it:
λ> run parseAnyChar "Hello"
Done ('H',"ello")
λ> run parseAnyChar ""
Fail "nothing to parse"

While it's not completely uncommon to define fmap = liftM and so on, this is a bit backwards IMO. If you first define the more fundamental instances and base the more involved ones on them, things often come out clearer. I'll leave <*> = ap, but transform everything else:
instance Functor Parser where -- Note that you can `derive` this automatically
fmap f (Done vs rest) = Done (map f vs) rest
fmap f (Fail err) = Fail err
instance Applicative Parser where
pure xs = Done ([], xs)
(<*>) = ap
Now with fmap already present, I can define Monad in the “more mathematical” way: define join instead of >>=.
instance Monad Parser where
return = pure
q >>= f = joinParser $ fmap f q
That means you'll work with intuitively handleable concrete values, rather than having to worry about threading a function through a parser. You can therefore see quite clearly what's going on, just write out the recursion:
joinParser :: Parser (Parser a) -> Parser a
joinParser (Fail err) = Fail err
joinParser (Done [] rest) = Done [] rest
joinParser (Done (Fail err : _) _) = Fail err
joinParser (Done (Done v0 rest0 : pss) rest) = ??
at this point you see clearly what Carsten already remarked: your Parser type doesn't really make sense as a parser. Both the inner and outer Done wrappers somehow have rest data; combining it would mean you combine the undone work... this is not what a parser does.
Search the web a bit, there's plenty of material on how to implement parsers in Haskell. In doubt, look how some established library does it, e.g. parsec.

Related

Modeling recursive fmap (sort of) over a list

I was wondering what the best way is to implement the following problem in a functional programming language (in this example Haskell):
You have a function (or a 'way') that turns 2 inputs, with the type a and b, in 2 ouputs of the same type (ex: Half adder). Lets call it f
in Haskell it would have this sort of type signature
a -> b -> (a, b)
And you have a list with elements of type a. (or another type of data structure).
Now if supplied with an initial b I want the following thing to happen (concept explained with recursive implementation):
Execute f with the initial b and the first element, modify the b and the element with the output of the function and repeat for the next element.
In Haskell:
exec _ [] _ = []
exec f (x:xs) b = let (x',b') = f x b in x':(exec f xs b')
What would be the best/most efficient way to model this sort of behavior.
It's mapM for the State monad.
OK, expanding a little.
Let's first enter this into ghci and see the type of the exec function:
Prelude> let {exec _ [] _ = []; exec f (x:xs) b = let (x',b') = f x b in x':(exec f xs b')}
Prelude> :t exec
exec :: (t2 -> t1 -> (t, t1)) -> [t2] -> t1 -> [t]
It's almost as you described, except that t and t2 don't have to be of the same type. That's good.
Now, another observation: we actually lose information, when we do what you describe. Specifically, we throw away the last value of b (or t, as ghci calls it). Let us preserve it for a moment; we can always throw it away later:
exec' _ [] b = ([], b)
exec' f (x:xs) b =
let (x',b') = f x b
(xs', b'') = exec' f xs b'
in (x':xs', b'')
And ghci says
Prelude> :t exec'
exec' :: (t2 -> t1 -> (t, t1)) -> [t2] -> t1 -> ([t], t1)
Than we can define
exec f xs b = fst $ exec' f xs b
But now the type of exec' contains a clear pattern. We can make it more explicit:
type S b c = b -> (c, b)
exec' :: (a -> S b c) -> [a] -> S b [c]
And now it's clear that S is almost exactly the State monad (well, it's actual definition in a modern setting is a bit more complicated, but not much: https://hackage.haskell.org/package/mtl-2.2.1/docs/Control-Monad-State-Lazy.html#t:StateT); really, it's just a newtype:
newtype State b c = State {runState :: b -> (c, b)}
And if we generalize the type of exec' to use an arbitrary monad instead of State, we get
Monad m => (a -> m c) -> [a] -> m [c]
Of course, we can't know for sure that such a thing actually exists, since we only have an implementation for the State monad, but... it does. It's called mapM (again, it's actual definition in the modern setting is more complicated: https://hackage.haskell.org/package/base-4.9.1.0/docs/Prelude.html#v:mapM) — which makes sense, since without a monad it would be just
(a -> c) -> [a] -> [c]
and that's exactly the type of map.
Of course, you can't be sure that exec' IS mapM without examining the latter's implementation. But in Haskell it just often happens that things that have the same type, if it's reasonably generic, are one and the same.
It also makes sense that State monad would be involved somehow — after all, you DO use b as a state, changing it as you go through the list.
So, if exec' is mapM, how do we get back to exec? Well, we need to go from the monadic value State b [c] to just [c], feeding it some b. We can — again — generalize; let's say, we go from State b d to d, without mentioning the list. And again — there is a function like that, it's called evalState: https://hackage.haskell.org/package/mtl-2.2.1/docs/Control-Monad-State-Lazy.html#v:evalState.
So, finally, we are able to produce the final result:
eval f xs b = evalState (mapM (\x -> state (\b -> f x b)) xs) b
which we can shorten to
eval f xs b = evalState (mapM (\x -> state (f x)) xs) b
or just
eval f xs = evalState (mapM (state . f) xs)
or even
eval f = evalState . mapM (state . f)
We can make it completely point-free, but that would be pointless (and contain too many points):
eval = (evalState .) . mapM . (state .)

You can find out if a list is a palindrome using (==) <*> reverse. How does it work?

I've tried to go through this using the types, but I'm still having difficulty understanding how it works.
Given:
> :t (==)
(==) :: Eq a => a -> a -> Bool
> :t (<*>)
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
> :t reverse
reverse :: [a] -> [a]
> :t (==) <*> reverse
(==) <*> reverse :: Eq a => [a] -> Bool
Intuitively I can understand that it combines the equality operator with reverse in such a way that it creates a function that checks if a reversed list is equal to the original, but that's really not much more information than what is already pretty obvious.
Could someone break down in more detail the internals of what is actually happening here?
Start with the type of (<*>)
> : t (<*>)
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
Now (->) k is an instance of Applicative, with implementation
instance Applicative ((->) k) where
pure a = \_ -> a
f <*> g = \k -> f k (g k)
In particular, the type of (<*>) specialised to (->) k is
(<*>) :: (k -> a -> b) -> (k -> a) -> (k -> b)
So the application (==) <*> reverse is
(==) <*> reverse = \k -> (==) k (reverse k)
= \k -> k == reverse k
i.e. it checks that a list is equal to its reverse.
Chris Taylor's answer is just right, but another way of looking at it, that I find more intuitive, is this: what the Applicative instance of function types does is this:
"Feed" the same argument value to two functions with the same argument type;
Combine their results with another function.
So basically, if you have f :: t -> a and g:: t -> b, the Applicative instance lets you map functions h :: a -> b -> c over the a and b results, under the assumption that f and g will be fed the same argument.
So think of how you'd write the palindrome test in a non-convoluted way:
palindrome :: Eq a => [a] -> Bool
palindrome xs = xs == reverse xs
xs appears twice on the right hand side of the definition: once as argument to ==, and a second time as argument to reverse. This automatically tells you that there is likely a way to use the (->) t applicative instance to eliminate the duplication. A different, perhaps more intuitive attack on this would be to first rewrite the function to this:
palindrome xs = id xs == reverse xs
...where id x = x is the identity function, which just returns its argument (and is a standard library function). Now you can rewrite that using the standard Applicative idiom (f <$> a0 <*> ... <*> an) to this:
-- Function that feed the same argument value to both `id` and `reverse`,
-- then tests their results with `==`:
palindrome = (==) <$> id <*> reverse
And now we can ask if there is a way to get rid of id in that rewrite. Since <$> is just shorthand for fmap, we can study the Functor instance for (->) t, which is just another way to express function composition:
instance Functor ((->) t) where
-- Mapping `f` over a *function* `g` is just the same as composing `f`
-- on the results of `g`.
fmap f g = f . g
One of the most important properties of function composition is that for any function f:
f . id = f
So applying that to the version of palindrome above, we get:
-- Since `f . id = f` for all `f`, then `(==) <$> id` is just `(==)`:
palindrome = (==) <*> reverse

Unit testing several implementations of a functional data structure without code duplication

As part of an assignment on functional data types, we're asked to give different implementations of queues in Haskell, two of which are given below.
Coming from an OO world, the first reflex is to let them implement a common interface such that they can e.g. share test code. From what we read up on Haskell, this translates into two data types that are instances of a common typeclass. This part was fairly straight-forward:
data SimpleQueue a = SimpleQueue [a]
data FancyQueue a = FancyQueue ([a], [a])
class Queue q where
empty :: q a
enqueue :: a -> q a -> q a
dequeue :: q a -> (a, q a)
instance Queue SimpleQueue where
empty = SimpleQueue []
enqueue e (SimpleQueue xs) = SimpleQueue $ xs ++ [e]
dequeue (SimpleQueue (x:xs)) = (x, SimpleQueue xs)
instance Queue FancyQueue where
empty = FancyQueue ([], [])
enqueue e (FancyQueue (h, t)) =
if length h > length t
then FancyQueue (h, e:t)
else FancyQueue (h ++ reverse (e:t), [])
dequeue (FancyQueue ((e:h), t)) =
if length h > length t
then (e, FancyQueue (h, t))
else (e, FancyQueue (h ++ reverse t, []))
After enormous amounts of fiddling around, we arrived at the following, working way of writing a test case (using HUnit) that tests both implementations using the same function f:
f :: (Queue q, Num a) => q a -> (a, q a)
f = dequeue . enqueue 4
makeTest = let (a, _) = f (empty :: SimpleQueue Int)
(b, _) = f (empty :: FancyQueue Int)
in assertEqual "enqueue, then dequeue" a b
test1 = makeTest
main = runTestTT (TestCase test1)
As the code suggests, we are very interested in letting the function makeTest take the test-function as a parameter, such that we can use it for generating several test cases without having to duplicate the code that applies the function all over them:
makeTest t = let (a, _) = t (empty :: SimpleQueue Int)
(b, _) = t (empty :: FancyQueue Int)
in assertEqual "enqueue, then dequeue" a b
test1 = makeTest f
main = runTestTT (TestCase test1)
This, however, fails to compile with the error
queue.hs:52:30:
Couldn't match expected type `FancyQueue Int'
with actual type `SimpleQueue Int'
In the first argument of `t', namely `(empty :: SimpleQueue Int)'
In the expression: t (empty :: SimpleQueue Int)
In a pattern binding: (a, _) = t (empty :: SimpleQueue Int)
Our question is if there is some way to make this work: Is it possible to write a function for generating our unit tests; one that takes a function and applies it to both implementations in such a way that we avoid duplicating the code that apply the function? Also, an explanation of the error above would be very welcome.
EDIT
Based on the answers below, here is what we end up with:
{-# LANGUAGE RankNTypes #-}
import Test.HUnit
import Queue
import SimpleQueue
import FancyQueue
makeTest :: String -> (forall q a. (Num a, Queue q) => q a -> (a, q a)) -> Assertion
makeTest msg t = let (a, _) = t (empty :: SimpleQueue Int)
(b, _) = t (empty :: FancyQueue Int)
in assertEqual msg a b
test1 = makeTest "enqueue, then dequeue" $ dequeue . enqueue 4
test2 = makeTest "enqueue twice, then dequeue" $ dequeue . enqueue 9 . enqueue 4
test3 = makeTest "enqueue twice, then dequeue twice" $ dequeue . snd . dequeue . enqueue 9 . enqueue 4
tests = TestList $ map (\ test -> TestCase test) [test1, test2, test3]
main = runTestTT tests
I was wondering if the type annotation on makeTest is the correct way to write it? I tried fiddling around with it, but this is the only thing that I could get to work. It's just that I thought that the part (Num a, Queue q) => should always be before the type itself. But maybe that's just a convention? Or is it all different for higher-rank types? Anyway, is it possible to write the type that way?
Also, not that it matters here, but out of curiosity; do the use of this extension impact performance (significantly)?
Yes, you need a language extension called Rank2Types. It allows functions like this
makeTest :: (forall q a. (Num a, Queue q) => q a -> (a, q a)) -> Assertion
makeTest t = let (a, _) = t (empty :: SimpleQueue Int)
(b, _) = t (empty :: FancyQueue Int)
in assertEqual "enqueue, then dequeue" a b
Now you're making sure that the function you receive is polymorphic so you can apply it to both a SimpleQueue and an FancyQueue.
Otherwise, Haskell is going to unify t's first argument with SimpleQueue and then become angry when you attempt it use it on a FancyQueue. In other words, by default Haskell makes function parameters monomorphic. To make them polymorphic though you will have to use an explicit signature, Haskell will not infer it.
To use this extension, you'll need to enable it with
{-# LANGUAGE RankNTypes #-}
at the top of your file. See here for a longer explanation on what this extension does and how it works.
Response to the edit
That's how it should correctly be typed. Haskell implicitly turns
foo :: Show a => a -> b -> c
into
foo :: forall a b c. Show a => a -> b -> c
With higher rank types, you're moving the forall into a lambda and the constraints move with it. You can't put the constraints all the way to the left because the relevant type variables aren't even in scope.
You are trying to use a function argument (namely t) at two different types. First at type SimpleQueue Int -> (Int, SimpleQueue Int) and then at FancyQueue Int -> (Int, FancyQueue Int). That is you really want the type of t to be polymorphic.
But by default in Haskell, function arguments are monomorphic. They may only be used at a single type. That type itself may be a type variable such as a, but within a single instance once you've picked what a is, that's the type it will always have.
The solution is to use the RankNTypes language extension and to give makeTest a rank-2 type:
{-# LANGUAGE RankNTypes #-}
module QueueTests where
...
makeTest :: (forall a q. (Num a, Queue q) => q a -> (a, q a)) -> Assertion
makeTest = -- same as before

Getting the head and tail of a custom list type in Haskell

I have a custom list type:
data NNList a = Sing a | Append ( NNList a) ( NNList a) deriving (Eq)
data CList a = Nil | NotNil ( NNList a) deriving (Eq)
I'm trying to implement a function that returns the head and tail of a list:
cListGet :: CList a -> Maybe (a, CList a)
My attempt:
cListGet :: CList a -> Maybe (a, CList a)
cListGet Nil = Nothing
cListGet xs#(NotNil nxs) =
case nxs of
Sing x -> (x, Nil)
Append l r -> ((fst $ cListGet (NotNil l)), (Append (snd $ cListGet (NotNil l)), r))
Which to me means keep going leftwards until I get a single. Once I get the single element (head), return the element and a Nil list. This Nil list is then combined with the list before it's returned as the final result.
I'm not even sure if the logic is 100% correct.
Well, people would normally refer to the data structure you have as a kind of tree, not as a list. But anyway...
Problem #1: Haskell is indentation sensitive, and your case expression is not indented. This leads to a parse error.
Problem #2, and the bigger one: you haven't understood how the Maybe type works yet. I get the impression that you think it works like nulls in more common languages, and this is throwing you off.
In a language like, say, Java, null is a value that can occur where most any other value can. If we have a method with the following signature:
public Foo makeAFoo(Bar someBar)
...then it is legal to call it either of these ways:
// Way #1: pass in an actual value
Bar theBar = getMeABar();
Foo result = makeAFoo(theBar);
// Way #2: pass in a null
Foo result2 = makeAFoo(null)
theBar and null are "parallel" in a sense, or said more precisely, they have the same type—you can replace one with the other in a program and it will compile in both cases.
In Haskell, on the other hand, the string "hello" and Nothing do not have the same type, and you cannot use one where the other goes. Haskell distinguishes between these three things:
A string that's required to be there: "hello" :: String
The absence of an optional string: Nothing :: Maybe String
The presence of an optional string: Just "hello" :: Maybe String
The difference between #1 and #3 is what you're systematically missing in your function. With Maybe a, in the cases where you do have a value you must use Just, which acts like a wrapper to signify "this isn't just an a, it's a Maybe a."
First place you're missing Just is the right hand sides of the case expressions, which we can fix like this:
-- This still fails to compile!
cListGet :: CList a -> Maybe (a, CList a)
cListGet Nil = Nothing
cListGet xs#(NotNil nxs) =
case nxs of
-- I added 'Just' here and in the next line:
Sing x -> Just (x, Nil)
Append l r -> Just (fst $ cListGet (NotNil l), (Append (snd $ cListGet (NotNil l)), r))
But this isn't the end of it, because you're doing fst $ cListGet (NotNil l), which suffers from the converse problem: cListGet returns Maybe (a, CList a), but fst works on (a, b), not on Maybe (a, b). You need to pattern match on the result of cListGet to test whether it's Nothing or Just (x, l'). (This same problem occurs also in your snd $ cListGet (NotNil l).)
Third, you're using your Append constructor wrong. You have it in the form of (Append foo, bar), which should have no comma between foo and bar. In Haskell this sort of thing will give you more confusing error messages than most other languages, because when Haskell sees this, it doesn't tell you "you made a syntax error"; Haskell is rather more literal than most languages, so it figures you're trying to make a pair with Append foo as the first element, and bar as the second one, so it concludes that (Append foo, bar) must have type (NNList a -> NNList a, NNList a).
The fourth and final problem: the problem you've set yourself is not clearly stated, and thus has no good answer. You say you want to find the "head" and "tail" of a CList a. What does that mean? In the case of the Haskell [a] type, with constructors [] and :, this is clear: the head is the x in x:xs, and the tail is the xs.
As I understand you, what you mean by "head" seems to be the leftmost element of the recursive structure. We could get that this way:
cListHead :: CList a -> Maybe a
cListHead Nil = Nothing
-- No need to cram everything together into one definition; deal with
-- the NNList case in an auxiliary function, it's easier...
cListGet (NotNil nxs) = Just (nnListHead nxs)
-- Note how much easier this function is to write, because since 'NNList'
-- doesn't have a 'Nil' case, there's no need to mess around with 'Maybe'
-- here. Basically, by splitting the problem into two functions, only
-- 'cListHead' needs to care about 'Maybe' and 'Just'.
nnListHead :: NNList a -> a
nnListHead (Sing a) = a
nnListHead (Append l _) = nnListHead l
So you might think that "the tail" is everything else. Well, the problem is that "everything else" is not a subpart of your CList or NNList. Take this example:
example :: CList Int
example = NotNil (Append (Append (Sing 1) (Sing 2)) (Sing 3))
The "head" is 1. But there is no subpart of the structure defined in example that contains 2 and 3 without containing 1 as well. You'd have to construct a new CList with a different shape than the original to get that. That's possible to do, but I don't see the value of it as a beginner's exercise, frankly.
In case it's not clear what I mean by a "subpart," think of the example as a tree:
NotNil
|
v
Append
/ \
v v
Sing Append
| / \
v v v
1 Sing Sing
| |
v v
2 3
Subpart = subtree.
Hint: try to rewrite this using only pattern matching and not equality-checking (==).
Edit:
First off, it's crucial that you understand what pattern matching is and how it works. I'd recommend going here and reading up; there are also plenty of other resources about this on the web (Google is your friend).
Once you've done that, here's another hint: First write a function nnListGet :: NNList a -> (a, CList a), then use it to implement cListGet.
Just to add to the other (very thorough) answers: It's good to realize that your custom list is a foldable structure. This means, it represents a sequence of values that can be combined together. Such datatypes can implement Foldable type class. In your case, it would be:
import Prelude hiding (foldr)
import Data.Foldable
data NNList a = Sing a | Append (NNList a) (NNList a) deriving (Eq)
data CList a = Nil | NotNil (NNList a) deriving (Eq)
instance Foldable NNList where
foldr f z (Sing x) = f x z
foldr f z (Append xs ys) = foldr f (foldr f z ys) xs
instance Foldable CList where
foldr _ z Nil = z
foldr f z (NotNil xs) = foldr f z xs
From that you'll get all functions defined in Data.Foldable for free, such as maximum/minimum, searching for an element etc.
For any Foldable, you can implement headMaybe that returns its first element by using First monoid. It's a very simple monoid that returns the left-most non-empty element. So if you fold all elements of a Foldable using this monoid, you'll get its first one:
import Data.Monoid
headMaybe :: (Foldable f) => f a -> Maybe a
headMaybe = getFirst . foldMap (First . Just)
(Alternatively, you can use foldr directly, using Maybe's instance of Alternative, which again returns the left-most non-empty element:
import Control.Applicative
headMaybe = foldr (\x y -> pure x <|> y) Nothing
.)
However, this doesn't solve the second part of your question - computing tailMaybe. This can't be defined in a generic way like headMaybe, and you'll need your custom function for that, as you did.
See also:
Fold on Wikipedia.
Foldable and Traversable on Haskell wiki.
Fold on Haskell wiki.
List processing on Haskell wikibook.
Why did you declare that in terms of two types? Here's a seemingly more appropriate type declaration with a correct function:
data CList a
= Nil
| Sing a
| Append (CList a) (CList a)
deriving (Eq)
headAndTail :: CList a -> Maybe (a, CList a)
headAndTail Nil = Nothing
headAndTail (Sing a) = Just (a, Nil)
headAndTail (Append a b) =
case headAndTail a of
Nothing -> headAndTail b
Just (head, tail) -> Just (head, Append tail b)

What's wrong with my recursive list construction?

I've simplified the functions in question. I'm having trouble constructing a list inside a monad. I suspect a precedence problem.
newtype Boundary = MkBoundary Integer
testFunc :: [Boundary] -> [Maybe Integer]
testFunc (MkBoundary x:xs)
| (even x) = Just x : testFunc xs
| otherwise = Nothing : testFunc xs
testFunc _ = []
This works as expected. But I need to work in a monad. I'll use IO for this example
testFunc :: [Boundary] -> IO [Maybe Integer]
testFunc (MkBoundary x:xs)
| (even x) = return $ Just x : testFunc xs
| otherwise = return $ Nothing : testFunc xs
testFunc _ = []
No matter how I try to manipulate precedence, this breaks.
test.hs:6:35:
Couldn't match expected type `[Maybe Integer]'
with actual type `IO [Maybe Integer]'
In the return type of a call of `testFunc'
In the second argument of `(:)', namely `testFunc xs'
In the second argument of `($)', namely `Just x : testFunc xs'
Failed, modules loaded: none.
What I am trying to accomplish is a constructing a list, then returning it to IO. What am I doing wrong?
luqui answered your question, I will note a useful combinator.
If you want to perform a monadic action for all elements of a list, use "mapM". It is defined as:
mapM f [] = return []
mapM f (x:xs) = do y <- f x
ys <- mapM f xs
return (y:ys)
or something equivalent. [If you know some other combinators, you can write mapM with liftM2 and foldr.]
testFunc = mapM f
where f (MkBoundary x) | even x = do print x
return $ Just x
| otherwise = return Nothing
test in GHCi:
*Main> testFunc [MkBoundary 2, MkBoundary 3, MkBoundary 4]
2
4
[Just 2,Nothing,Just 4]
The problem is that testFunc xs returns an IO [Maybe Integer], and you are using it as the tail of a list as if it were a [Maybe Integer]. You need to extract:
| (even x) = do
xs' <- testFunc xs
-- now xs' is of type [Maybe Integer]
return $ Just x : xs'
Or, a more succinct way of saying the same thing:
| (even x) = (Just x :) <$> testFunc xs
((<$>) is from Control.Applicative and has type
(<$>) :: (a -> b) -> IO a -> IO b
specialized to IO . It applies a function to the value "inside" a monadic computation.)
Oh, also what missingno said :-)
You forgot to change the second case
test_func _ = return []
-- ^^^^^^
Also, I think your example function could be more clearly written as
test_func :: [Boundary] -> [Maybe Integer]
test_func = ...
monadic_test_func = [Boundary] -> IO [Maybe Integer]
monadic_test_func = return . test_func
This keeps the pure code separated from the nasty monad stuff. It also saves you from having to type "return" thrice! :)
And finally, why are you creating such a function in the first place? The monad part (at least in your example) seems to be somewhat unrelated to the main function logic (since you are just doing a return).
Perhaps you use some nice library functions to keep your function pure and untouched?
--instead of
monadic_value >>= monadic_test_func
--use
fmap test_func monadic_value
-- or equivalently
test_func <$> monadic_value
liftM test_func monadic_value