I was playing around with composable failures and managed to write a function with the signature
getPerson :: IO (Maybe Person)
where a Person is:
data Person = Person String Int deriving Show
It works and I've written it in the do-notation as follows:
import Control.Applicative
getPerson = do
name <- getLine -- step 1
age <- getInt -- step 2
return $ Just Person <*> Just name <*> age
where
getInt :: IO (Maybe Int)
getInt = do
n <- fmap reads getLine :: IO [(Int,String)]
case n of
((x,""):[]) -> return (Just x)
_ -> return Nothing
I wrote this function with the intent of creating composable possible failures. Although I've little experience with monads other than Maybe and IO this seems like if I had a more complicated data type with many more fields, chaining computations wouldn't be complicated.
My question is how would I rewrite this without do-notation? Since I can't bind values to names like name or age I'm not really sure where to start.
The reason for asking is simply to improve my understanding of (>>=) and (<*>) and composing failures and successes (not to riddle my code with illegible one-liners).
Edit: I think I should clarify, "how should I rewrite getPerson without do-notation", I don't care about the getInt function half as much.
Do-notation desugars to (>>=) syntax in this manner:
getPerson = do
name <- getLine -- step 1
age <- getInt -- step 2
return $ Just Person <*> Just name <*> age
getPerson2 =
getLine >>=
( \name -> getInt >>=
( \age -> return $ Just Person <*> Just name <*> age ))
each line in do-notation, after the first, is translated into a lambda which is then bound to the previous line. It's a completely mechanical process to bind values to names. I don't see how using do-notation or not would affect composability at all; it's strictly a matter of syntax.
Your other function is similar:
getInt :: IO (Maybe Int)
getInt = do
n <- fmap reads getLine :: IO [(Int,String)]
case n of
((x,""):[]) -> return (Just x)
_ -> return Nothing
getInt2 :: IO (Maybe Int)
getInt2 =
(fmap reads getLine :: IO [(Int,String)]) >>=
\n -> case n of
((x,""):[]) -> return (Just x)
_ -> return Nothing
A few pointers for the direction you seem to be headed:
When using Control.Applicative, it's often useful to use <$> to lift pure functions into the monad. There's a good opportunity for this in the last line:
Just Person <*> Just name <*> age
becomes
Person <$> Just name <*> age
Also, you should look into monad transformers. The mtl package is most widespread because it comes with the Haskell Platform, but there are other options. Monad transformers allow you to create a new monad with combined behavior of the underlying monads. In this case, you're using functions with the type IO (Maybe a). The mtl (actually a base library, transformers) defines
newtype MaybeT m a = MaybeT { runMaybeT :: m (Maybe a) }
This is the same as the type you're using, with the m variable instantiated at IO. This means you can write:
getPerson3 :: MaybeT IO Person
getPerson3 = Person <$> lift getLine <*> getInt3
getInt3 :: MaybeT IO Int
getInt3 = MaybeT $ do
n <- fmap reads getLine :: IO [(Int,String)]
case n of
((x,""):[]) -> return (Just x)
_ -> return Nothing
getInt3 is exactly the same except for the MaybeT constructor. Basically, any time you have an m (Maybe a) you can wrap it in MaybeT to create a MaybeT m a. This gains simpler composability, as you can see by the new definition of getPerson3. That function doesn't worry about failure at all because it's all handled by the MaybeT plumbing. The one remaining piece is getLine, which is just an IO String. This is lifted into the MaybeT monad by the function lift.
Edit
newacct's comment suggests that I should provide a pattern matching example as well; it's basically the same with one important exception. Consider this example (the list monad is the monad we're interested in, Maybe is just there for pattern matching):
f :: Num b => [Maybe b] -> [b]
f x = do
Just n <- x
[n+1]
-- first attempt at desugaring f
g :: Num b => [Maybe b] -> [b]
g x = x >>= \(Just n) -> [n+1]
Here g does exactly the same thing as f, but what if the pattern match fails?
Prelude> f [Nothing]
[]
Prelude> g [Nothing]
*** Exception: <interactive>:1:17-34: Non-exhaustive patterns in lambda
What's going on? This particular case is the reason for one of the biggest warts (IMO) in Haskell, the Monad class's fail method. In do-notation, when a pattern match fails fail is called. An actual translation would be closer to:
g' :: Num b => [Maybe b] -> [b]
g' x = x >>= \x' -> case x' of
Just n -> [n+1]
_ -> fail "pattern match exception"
now we have
Prelude> g' [Nothing]
[]
fails usefulness depends on the monad. For lists, it's incredibly useful, basically making pattern matching work in list comprehensions. It's also very good in the Maybe monad, since a pattern match error would lead to a failed computation, which is exactly when Maybe should be Nothing. For IO, perhaps not so much, as it simply throws a user error exception via error.
That's the full story.
do-blocks of the form var <- e1; e2 desugar to expressions using >>= as follows e1 >>= \var -> e2. So your getPerson code becomes:
getPerson =
getLine >>= \name ->
getInt >>= \age ->
return $ Just Person <*> Just name <*> age
As you see this is not very different from the code using do.
Actually, according to this explaination, the exact translation of your code is
getPerson =
let f1 name =
let f2 age = return $ Just Person <*> Just name <*> age
f2 _ = fail "Invalid age"
in getInt >>= f2
f1 _ = fail "Invalid name"
in getLine >>= f1
getInt =
let f1 n = case n of
((x,""):[]) -> return (Just x)
_ -> return Nothing
f1 _ = fail "Invalid n"
in (fmap reads getLine :: IO [(Int,String)]) >>= f1
And the pattern match example
f x = do
Just n <- x
[n+1]
translated to
f x =
let f1 Just n = [n+1]
f1 _ = fail "Not Just n"
in x >>= f1
Obviously, this translated result is less readable than the lambda version, but it works with or without pattern matching.
Related
Not using formal deduction, how can I test whether a self-defined Monad instance follows the Monad laws?
FWIW, here's a set of QuickCheck properties I recently wrote that tests the Monad laws for a Maybe implementation derived from its F-Algebra:
testProperty "Monad left identity law" $ do
a :: String <- arbitrary
k :: String -> MaybeFix Integer <- (fromMaybe .) <$> arbitrary
let left = return a >>= k
let right = k a
return $ left == right
,
testProperty "Monad right identity law" $ do
m :: MaybeFix Integer <- fromMaybe <$> arbitrary
let left = m >>= return
let right = m
return $ left == right
,
testProperty "Monad associativity law" $ do
m :: MaybeFix String <- fromMaybe <$> arbitrary
k :: String -> MaybeFix Integer <- (fromMaybe .) <$> arbitrary
h :: Integer -> MaybeFix Ordering <- (fromMaybe .) <$> arbitrary
let left = m >>= (\x -> k x >>= h)
let right = (m >>= k) >>= h
return $ left == right
I suppose you know what Monad laws are, but I'll link them for the sake of completeness.
Since you explicitly mentioned testing as opposed to formal proving, you can use one of the automated testing frameworks for Haskell, e.g. QuickCheck or Hspec.
This may be a bit over the top, but you can try hs-to-coq, which might be able to convert your hs code to Coq code, which you can then prove things about using Coq (a Proof Assistant).
For an example of proving monad laws using Coq (though this was not using hs-to-coq), see:
https://github.com/jwiegley/coq-pipes#laws-proven
Somewhat mystified by the following code. In non-toy version of the problem I'm trying to do a monadic computation in a monad Result, the values of which can only be constructed from within IO. Seems like the magic behind IO makes such computations strict, but I can't figure out how exactly that happens.
The code:
data Result a = Result a | Failure deriving (Show)
instance Functor Result where
fmap f (Result a) = Result (f a)
fmap f Failure = Failure
instance Applicative Result where
pure = return
(<*>) = ap
instance Monad Result where
return = Result
Result a >>= f = f a
Failure >>= _ = Failure
compute :: Int -> Result Int
compute 3 = Failure
compute x = traceShow x $ Result x
compute2 :: Monad m => Int -> m (Result Int)
compute2 3 = return Failure
compute2 x = traceShow x $ return $ Result x
compute3 :: Monad m => Int -> m (Result Int)
compute3 = return . compute
main :: IO ()
main = do
let results = mapM compute [1..5]
print $ results
results2 <- mapM compute2 [1..5]
print $ sequence results2
results3 <- mapM compute3 [1..5]
print $ sequence results3
let results2' = runIdentity $ mapM compute2 [1..5]
print $ sequence results2'
The output:
1
2
Failure
1
2
4
5
Failure
1
2
Failure
1
2
Failure
Nice test cases. Here's what's happening:
in mapM compute we see laziness at work, as usual. No surprise here.
in mapM compute2 we work inside the IO monad, whose mapM definition will demand the whole list: unlike Result which skips the tail of the list as soon as Failure is found, IO will always scan the whole list. Note the code:
compute2 x = traceShow x $ return $ Result x
So, the above wil print the debug message as soon as each element of the list of IO actions is accessed. All are, so we print everything.
in mapM compute3 we now use, roughly:
compute3 x = return $ traceShow x $ Result x
Now, since return in IO is lazy, it will not trigger the traceShow when returning the IO action. So, when mapM compute3 is run, no message is seen. Instead, we see messages only when sequence results3 is run, which forces the Result -- not all of them, but only as much as needed.
the final Identity example is also quite tricky. Note this:
> newtype Id1 a = Id1 a
> data Id2 a = Id2 a
> Id1 (trace "hey!" True) `seq` 42
hey!
42
> Id2 (trace "hey!" True) `seq` 42
42
when using a newtype, at runtime there is no boxing/unboxing (AKA lifting) involved, so forcing a Id1 x value causes x to be forced. With data types this does not happen: the value is wrapped in a box (e.g. Id2 undefined is not equivalent to undefined).
In your example, you add an Identity constructor, but that is from the newtype Identity!! So, when calling
return $ traceShow x $ Result x
the return here does not wrap anything, and the traceShow is immediately triggered as soon as mapM is run.
Your Result type appears to be virtually identical to Maybe, with
Result <-> Just
Failure <-> Nothing
For the sake of my poor brain, I'll stick to Maybe terminology in the rest of this answer.
chi explained why IO (Maybe a) does not short-circuit the way you expected. But there is a type you can use for this sort of thing! It's essentially the same type, in fact, but with a different Monad instance. You can find it in Control.Monad.Trans.Maybe. It looks something like this:
newtype MaybeT m a = MaybeT
{ runMaybeT :: m (Maybe a) }
As you can see, this is just a newtype wrapper around m (Maybe a). But its Monad instance is very different:
instance Monad m => Monad (MaybeT m) where
return a = MaybeT $ return (Just a)
m >>= f = MaybeT $ do
mres <- runMaybeT m
case mres of
Nothing -> return Nothing
Just a -> runMaybeT (f a)
That is, m >>= f runs the m computation in the underlying monad, getting Maybe something or other. If it gets Nothing, it just stops, returning Nothing. If it gets something, it passes that to f and runs the result. You can also turn any m action into a "successful" MaybeT m action using lift from Control.Monad.Trans.Class:
class MonadTrans t where
lift :: Monad m => m a -> t m a
instance MonadTrans MaybeT where
lift m = MaybeT $ Just <$> m
You can also use this class, defined somewhere like Control.Monad.IO.Class, which is often clearer and can be much more convenient:
class MonadIO m where
liftIO :: IO a -> m a
instance MonadIO IO where
liftIO m = m
instance MonadIO m => MonadIO (MaybeT m) where
liftIO m = lift (liftIO m)
I'm new to Haskell and FP so this question may seem silly.
I have a line of code in my main function
let y = map readFile directoryContents
where directoryContents is of type [FilePath]. This in turn (I think) makes y type [IO String] , so a list of strings - each string containing the contents of each file in directoryContents.
I have a functions written in another module that work on [String] and String but I'm unclear as how to call/use them now because y is of type [IO String]. Any pointers?
EDIT:
It was suggested to me that I want to use mapM instead of map, so:
let y = mapM readFile directoryContents , and y is now type IO [String], what do I do from here?
You're correct, the type is y :: [IO String].
Well, there are essentially main two parts here:
How to turn [IO String] into IO [String]
[IO String] is a list of of IO actions and what we need is an IO action that carries a list of strings (that is, IO [String]). Luckily, the function sequence provides exactly what we need:
sequence :: Monad m => [m a] -> m [a]
y' = sequence y :: IO [String]
Now the mapM function can simplify this, and we can rewrite y' as:
y' = mapM readFile directoryContents
mapM does the sequence for us.
How to get at the [String]
Our type is now IO [String], so the question is now "How do we get the [String] out of the IO?" This is what the function >>= (bind) does:
(>>=) :: Monad m => m a -> (a -> m b) -> m b
-- Specialized to IO, that type is:
(>>=) :: IO a -> (a -> IO b) -> IO b
We also have a function return :: Monad m => a -> m a which can put a value "into" IO.
So with these two functions, if we have some function f :: [String] -> SomeType, we can write:
ourResult = y' >>= (\theStringList -> return (f theStringList)) :: IO SomeType
Functions can be "chained" together with the >>= function. This can be a bit unreadable at times, so Haskell provides do notation to make things visually simpler:
ourResult = do
theStringList <- y'
return $ f theStringList
The compiler internally turns this into y' >>= (\theStringList -> f theStringList), which is the same as the y' >>= f that we had before.
Putting it all together
We probably don't actually want y' floating around, so we can eliminate that and arrive at:
ourResult = do
theStringList <- mapM readFile directoryContents
return $ f theStringList
Even more simplification
It turns out, this doesn't actually need the full power of >>=. In fact, all we need is fmap! This is because the function f only has one argument "inside" of IO and we aren't using any other previous IO result: we're making a result then immediately using it.
Using the law
fmap f xs == xs >>= return . f
we can rewrite the >>= code to use fmap like this:
ourResult = fmap f (mapM readFile directoryContents)
If we want to be even more terse, there is an infix synonym for fmap called <$>:
ourResult = f <$> mapM readFile directoryContents
I'm writing a prompt - response style system with a bunch of various combinations of Maybe a, IO a, and MaybeT IO a, and there is a lof of stuff to take into account. Some IO actions for which there is no invalid input (and therefore aren't wrapped in MaybeT), some which are (and return an MaybeT IO a) some which aren't IO actions but can fail, so return Maybe a, and some that are just plain values and its beginning to seem that I have to remember inordinate combinations of <$>, Just, fmap, MaybeT, lift, =<<, and return just to get everything to be the right type. Is there any easier way to manage this or to reason about what functions I need to use to get my values where I need them? Or do I just have to hope I get better at it with time? Here is my example:
getPiece :: Player -> Board -> MaybeT IO Piece
getPiece player#(Player pieces _ _ _) board = piece
where
promptString = displayToUserForPlayer player board ++ "\n" ++ (display player) ++ "\n" ++ "Enter piece number: "
input :: MaybeT IO String
input = lift $ prompt promptString
index :: MaybeT IO Int
index = MaybeT <$> return <$> ((fmap cvtFrom1indexedInt) . maybeRead) =<< input
piece :: MaybeT IO Piece
piece = MaybeT <$> return <$> maybeIndex pieces =<< index
getRotatedPiece :: Player -> Board -> MaybeT IO Piece
getRotatedPiece player#(Player pieces _ _ _) board = piece
where
promptString :: MaybeT IO String
promptString = (++) <$> displayListString <*> restOfString
input :: MaybeT IO String
input = MaybeT <$> (fmap Just) <$> prompt =<< promptString
index :: MaybeT IO Int
index = MaybeT <$> return <$> ((fmap cvtFrom1indexedInt) . maybeRead) =<< input
piece :: MaybeT IO Piece
piece = MaybeT <$> return <$> maybeIndex pieces =<< index
rotatedPieceList :: MaybeT IO [Piece]
rotatedPieceList = rotations <$> getPiece player board
displayListString :: MaybeT IO String
displayListString = displayNumberedList <$> rotatedPieceList
restOfString :: MaybeT IO String
restOfString = MaybeT <$> return <$> Just $ "\nEnter rotation number:"
I must say, I am disappointed at the lack of conciseness, even if I removed the type hints I could likely write a shorter function to do the same thing in C# or python
Since you provided only a code fragment, I cannot try to refactor it. However, this is what I'd do: Most monads have a corresponding type class. The reason for it is exactly what you need here: When you create a monad using a monad transformer, it will inherit the operations of the inner monads (if appropriate). So you can forget about the inner monads and work just within the final monad.
In your case, you have MaybeT IO. It's instance of MonadPlus and of MonadIO. So you can refactor the code that returns Maybe something to work with a general MonadPlus instance instead, just replace Just with return and Nothing with mzero. Like:
-- before
checkNumber :: Int -> Maybe Int
checkNumber x | x > 0 = Just x
| otherwise = Nothing x
-- after
checkNumber :: MonadPlus m => Int -> m Int
checkNumber x | x > 0 = return x
| otherwise = mzero
-- or just: checkNumber = mfilter (> 0) . return
It will work with any MonadPlus, including Maybe and MaybeT IO.
And you can refactor the code that returns IO something to work with a general MonadIO instance:
-- before
doSomeIO :: IO ()
doSomeIO = getLine >>= putStrLn
-- after
doSomeIO :: MonadIO m => m ()
doSomeIO = liftIO $ getLine >>= putStrLn
This way, you can forget about <$>/fmap/liftM, Just, MaybeT etc. You just use return, mzero and in some places liftIO.
This will also help you to create a more general code. If you later realize that you need to add something to the monad stack, the existing code won't break, as long as the new monad stack implements the same type classes.
A less ambitious answer from me. Looking at your code, your operations like getPiece don't really return any information from the a particular error site. You can probably get away with just using IO and turning exceptions into Maybe values if you really want those. Some sample code I put together with some undefined functions referenced in your code:
import Control.Exception (handle, IOException)
data Board = Board deriving (Show)
data Piece = Piece deriving (Show)
type Pieces = [Piece]
data Player = Player Pieces () () () deriving (Show)
prompt :: String -> IO String
prompt = undefined
cvtFrom1indexedInt :: Int -> Int
cvtFrom1indexedInt = undefined
maybeIndex :: Pieces -> Int -> Maybe Piece
maybeIndex = undefined
displayToUserForPlayer :: Player -> Board -> String
displayToUserForPlayer = undefined
display :: Player -> String
display = undefined
-- I used this when testing, to deal with the Prelude.undefined errors
--returnSilently :: SomeException -> IO (Maybe a)
returnSilently :: IOException -> IO (Maybe a)
returnSilently e = return Nothing
getPiece :: Player -> Board -> IO (Maybe Piece)
getPiece player#(Player pieces _ _ _) board = handle returnSilently $ do
let promptString = displayToUserForPlayer player board ++ "\n" ++ (display player) ++ "\n" ++ "Enter piece number: "
input <- prompt promptString
let index = cvtFrom1indexedInt (read input)
return (maybeIndex pieces index)
main = do
maybePiece <- getPiece (Player [] () () ()) Board
putStrLn ("Got piece: " ++ show maybePiece)
Notably I've moved from MaybeT IO Piece to just IO (Maybe Piece). Instead of using fmap or lift I've just used do notation for referring to the intermediate results of my IO action.
Going on your comments about C# or Python, I hope this was the sort of simpler answer you were looking for.
Particularly, I need to be able to combine the CGI monad with the IO monad, but an example of how to combine the IO monad with the Maybe monad might be even better...
I assume you want to use the Maybe monad for early termination (like break or return in C).
In that case you should use MaybeT from the MaybeT package (cabal install MaybeT).
main = do
runMaybeT . forever $ do
liftIO $ putStrLn "I won't stop until you type pretty please"
line <- liftIO getLine
when ("pretty please" == line) mzero
return ()
MaybeT is a monad transformer version of the maybe monad.
Monad transformers "add functionality" to other monads.
You don't exactly say how you want to combine IO and Maybe, but I assume you have many functions that return IO (Maybe a) that you want to combine easily. Basically you want to treat IO (Maybe a) as a separate type with it's own Monad instance:
newtype IOMaybe a = IOM (IO (Maybe a))
-- "unpack" a value of the new type
runIOMaybe :: IOMaybe a -> IO (Maybe a)
runIOMaybe (IOM a) = a
instance Monad IOMaybe where
-- bind operator
(IOM ioa) >>= f = IOM $ do
a <- ioa
case a of
Nothing -> return Nothing
Just v -> runIOMaybe (f v)
-- return
return a = IOM (return (Just a))
-- maybe also some convenience functions
returnIO :: IO a -> IOMaybe a
returnIO ioa = IOM $ do
v <- ioa
return (Just v)
returnMaybe :: Maybe a -> IOMaybe a
returnMaybe ma = IOM (return ma)
With this you can use the do-Notation to combine functions that return IO (Maybe a), IO a or Maybe a:
f1 :: Int -> IO (Maybe Int)
f1 0 = return Nothing
f1 a = return (Just a)
main = runIOMaybe $ do
returnIO $ putStrLn "Hello"
a <- returnMaybe $ Just 2
IOM $ f1 a
return ()
Generally something that combines and modifies monads like this is called a monad transformer, and GHC comes with a package that includes monad transformers for common cases. If there is something in this monad transformer library that fits your scenario depends on how exactly you want to combine Maybe and IO.
In what sense do you want to combine the monads?
f :: Int -> IO (Maybe Int)
f x = do
putStrLn "Hello world!"
return $ if x == 0 then Nothing else Just x
Can be evaluated to:
[1 of 1] Compiling Main ( maybe-io.hs, interpreted )
Ok, modules loaded: Main.
*Main> f 0
Hello world!
Nothing
*Main> f 3
Hello world!
Just 3