How can this code (or in general, code with multiple inputs) can be reduced/simplified?
do
sex <- askSex
name <- askName
sayHello sex name
In this case is very short already, but when it gets to multiple inputs, it looks messy. Is there any way to do something like:
sayHello askSex askName
?
If you
import Control.Applicative -- for <$> and <*>
import Control.Monad -- for join
you can write
join $ sayHello <$> askSex <*> askName
For your example, where you are only fetching two parameters, this is not a big win. But for a greater number of parameters it can make the code clearer.
join $ doSomething <$> getFirst <*> getSecond <*> getThird <*> getForth
This is a lovely time for Applicative Functors:
import Control.Applicative -- at the top of your module before any functions
hello "Male" name = "Hi, " ++ name ++ ", that's a cool name."
hello "Female" name = "Hello, " ++ name ++ ", that's a pretty name."
greet = hello <$> askSex <*> askName >>= putStrLn
It works a bit like fmap in the previous answers I gave you today, but for larger numbers of arguments, like you have here.
Using functions like my hello with applicative functors helps you separate your IO code from the rest of the code, which is very good practice. Try to write hello instead of sayHello every time.
Annoyingly, hoogle doesn't have an easy answer for this one. This would be called bind2. If it's a function with only one input, then you can use =<<, the infix version of what I'd call bind1.
sayHello =<< askName
But for multiple inputs, we're out of luck. For whatever reason, the standard libs don't provide this:
bind2 :: Monad m => (a -> b -> m c) -> m a -> m b -> m c
bind2 f mx my = do
x <- mx
y <- my
f x y
...
bind2 sayHello askSex askName
You can, of course, just define it yourself.
Related
I was following this tutorial https://blog.ssanj.net/posts/2014-09-23-A-Simple-Reader-Monad-Example.html
It has tree functions that is embarrassing to me
tom :: Reader String String
tom = do
env <- ask
return (env ++ " This is tom.")
jerry :: Reader String String
jerry = do
env <- ask
return (env ++ " This is Jerry.")
tomAndJerry :: Reader String String
tomAndJerry = do
t <- tom
j <- jerry
return (t ++ "\n" ++ j)
runJerryRun :: String
runJerryRun = (runReader tomAndJerry) "Who is this?"
These functions receive no arguments but still they access the reader monad, what magic is happening here? What is the intuition behind this?
I reader monad a kind of global?
Each of the first two functions returns its own instance of a Reader monad. Then, you can compose them together (in the third function).
For the sake of the argument, let's replace Reader with IO and do something similar, with none of these functions receiving any argument:
getIntFromFile :: IO Int
getIntFromFile = do
x <- readFile "myfile.txt"
pure $ read x :: Int
getIntFromStdin :: IO Int
getIntFromStdin = do
x <- getLine
pure $ read x :: Int
As you can see, both use the IO monad but they don't share anything in common. However, since they both use the IO monad, you can (and that's the beauty of it) compose them together as follows:
-- | the equivalent of your `tomAndJerry` function
main :: IO ()
main = do
x <- getIntFromFile
y <- getIntFromStdin
print $ x + y
This is exactly the same logic at play with the example from the tutorial, except with Reader instead of IO.
I think one important misunderstanding was addressed by Daniel Wagner in a comment. The Reader is (well, wraps) a function, so it does take arguments. In light of this, I guess your final question
I reader monad a kind of global?
has an answer: yes, in the sense that the reader monad gives you a way to pass an immutable state/environment through chained computations; so it kind of reads the same value everytime it's invoked (via ask) along the chain.
Which in the case of your code means that the two asks (or, equivalently, tom and jerry) both read the same environment, represented by the string "Who is this?".
Imho, this becomes a bit clearer by desugaring the dos:
tom :: Reader String String
tom = ask >>= \env -> return (env ++ " This is Tom.")
jerry :: Reader String String
jerry = ask >>= \env -> return (env ++ " This is Jerry.")
tomAndJerry :: Reader String String
tomAndJerry = tom >>= \t -> jerry >>= \j -> return (t ++ "\n" ++ j)
Here >>= expects a function that returns a monad, but you don't have it, you have the "ordinary" function (e.g. \env -> env ++ " This is Tom."), so you have to use return to wrap the result back into the monad. Then instead of using >>= and return . f, why don't we use fmap f, since we only have to apply a function inside the monad?
Which means that we can go further and simplify by using Functor for tom and jerry and Applicative for tomAndJerry.
tom :: Reader String String
tom = fmap (++ " This is Tom.") ask
jerry :: Reader String String
jerry = fmap (++ " This is Jerry.") ask
tomAndJerry :: Reader String String
tomAndJerry = (\t j -> t ++ "\n" ++ j) <$> tom <*> jerry
Both tom and jerry are asking for the environment, and each of them applies a function to it. Then tomAndJerry is just a way of composing them via a binary function, as pointed out in the accepted answer.
By the way, the language server tells me of asks, which allows to write
tom :: Reader String String
tom = asks (++ " This is Tom.")
I am trying to get a good grip on the do notation in Haskell.
I could use it with Maybe and then print the result. Like this:
maybeAdd :: Maybe Integer
maybeAdd = do one <- maybe1
two <- maybe2
three <- maybe3
return (one + two + three)
main :: IO ()
main = putStr (show $ fromMaybe 0 maybeAdd)
But instead of having a separate function I am trying to use the do notation with the Maybe inside the main function. But I am not having any luck. The various attempts I tried include:
main :: IO ()
main = do one <- maybe1
two <- maybe2
three <- maybe3
putStr (show $ fromMaybe 0 $ return (one + two + three))
main :: IO ()
main = do one <- maybe1
two <- maybe2
three <- maybe3
putStr (show $ fromMaybe 0 $ Just (one + two + three))
main :: IO ()
main = do one <- maybe1
two <- maybe2
three <- maybe3
putStr (show $ (one + two + three))
All of these leads to various types of compilation errors, which unfortunately I failed to decipher to get the correct way to do it.
How do I achieve the above? And perhaps maybe an explanation of why the approaches I tried were wrong also?
Each do block must work within a single monad. If you want to use multiple monads, you could use multiple do blocks. Trying to adapt your code:
main :: IO ()
main = do -- IO block
let x = do -- Maybe block
one <- maybe1
two <- maybe2
three <- maybe3
return (one + two + three)
putStr (show $ fromMaybe 0 x)
You could even use
main = do -- IO block
putStr $ show $ fromMaybe 0 $ do -- Maybe block
one <- maybe1
two <- maybe2
three <- maybe3
return (one + two + three)
-- other IO actions here
but it could be less readable in certain cases.
The MaybeT monad transformer would come handy in this particular case. MaybeT monad transformer is just a type defined something like;
newtype MaybeT m a = MaybeT {runMaybeT :: m (Maybe a)}
Actually transformers like MaybeT, StateT etc, are readily available in Control.Monad.Trans.Maybe, Control.Monad.Trans.State... For illustration purposes it' Monad instance could be something like shown below;
instance Monad m => Monad (MaybeT m) where
return = MaybeT . return . Just
x >>= f = MaybeT $ runMaybeT x >>= g
where
g Nothing = return Nothing
g (Just x) = runMaybeT $ f x
so as you will notice the monadic f function takes a value that resides in the Maybe monad which itself is in another monad (IO in our case). The f function does it's thing and wraps the result back into MaybeT m a.
Also there is a MonadTrans class where you can have some common functionalities those are used by the transformer types. One such is lift which is used to lift the value into a transformer according to that particular instance's definition. For MaybeT it should look like
instance MonadTrans MaybeT where
lift = MaybeT . (liftM Just)
Lets perform your task with monad transformers.
addInts :: MaybeT IO ()
addInts = do
lift $ putStrLn "Enter two integers.."
i <- lift getLine
guard $ test i
j <- lift getLine
guard $ test j
lift . print $ (read i :: Int) + (read j :: Int)
where
test = and . (map isDigit)
So when called like
λ> runMaybeT addInts
Enter two integers..
1453
1571
3024
Just ()
The catch is, since a monad transformer is also a member of Monad typeclass, one can nest them indefinitelly and still do things under a singe do notation.
Edit: answer gets downvoted but it is unclear to me why. If there is something wrong with the approach please care to elaborate me so that it helps people including me to learn something better.
Taking the opportunity of being on the edit session, i would like to add a better code since i think Char based testing might not be the best idea as it will not take negative Ints into account. So let's try using readMaybe from the Text.Read package while we are doing things with the Maybe type.
import Control.Monad.Trans.Maybe
import Control.Monad.Trans.Class (lift)
import Text.Read (readMaybe)
addInts :: MaybeT IO ()
addInts = do
lift $ putStrLn "Enter two integers.."
i <- lift getLine
MaybeT $ return (readMaybe i :: Maybe Int)
j <- lift getLine
MaybeT $ return (readMaybe j :: Maybe Int)
lift . print $ (read i :: Int) + (read j :: Int)
I guess now it works better...
λ> runMaybeT addInts
Enter two integers..
-400
500
100
Just ()
λ> runMaybeT addInts
Enter two integers..
Not an Integer
Nothing
I'm trying to write code in source -> transform -> sink style, for example:
let (|>) = flip ($)
repeat 1 |> take 5 |> sum |> print
But would like to do that using IO. I have this impression that my source can be an infinite list of IO actions, and each one gets evaluated once it is needed downstream. Something like this:
-- prints the number of lines entered before "quit" is entered
[getLine..] >>= takeWhile (/= "quit") >>= length >>= print
I think this is possible with the streaming libraries, but can it be done along the lines of what I'm proposing?
Using the repeatM, takeWhile and length_ functions from the streaming library:
import Streaming
import qualified Streaming.Prelude as S
count :: IO ()
count = do r <- S.length_ . S.takeWhile (/= "quit") . S.repeatM $ getLine
print r
This seems to be in that spirit:
let (|>) = flip ($)
let (.>) = flip (.)
getContents >>= lines .> takeWhile (/= "quit") .> length .> print
The issue here is that Monad is not the right abstraction for this, and attempting to do something like this results in a situation where referential transparency is broken.
Firstly, we can do a lazy IO read like so:
module Main where
import System.IO.Unsafe (unsafePerformIO)
import Control.Monad(forM_)
lazyIOSequence :: [IO a] -> IO [a]
lazyIOSequence = pure . go where
go :: [IO a] -> [a]
go (l:ls) = (unsafePerformIO l):(go ls)
main :: IO ()
main = do
l <- lazyIOSequence (repeat getLine)
forM_ l putStrLn
This when run will perform cat. It will read lines and output them. Everything works fine.
But consider changing the main function to this:
main :: IO ()
main = do
l <- lazyIOSequence (map (putStrLn . show) [1..])
putStrLn "Hello World"
This outputs Hello World only, as we didn't need to evaluate any of l. But now consider replacing the last line like the following:
main :: IO ()
main = do
x <- lazyIOSequence (map (putStrLn . show) [1..])
seq (head x) putStrLn "Hello World"
Same program, but the output is now:
1
Hello World
This is bad, we've changed the results of a program just by evaluating a value. This is not supposed to happen in Haskell, when you evaluate something it should just evaluate it, not change the outside world.
So if you restrict your IO actions to something like reading from a file nothing else is reading from, then you might be able to sensibly lazily evaluate things, because when you read from it in relation to all the other IO actions your program is taking doesn't matter. But you don't want to allow this for IO in general, because skipping actions or performing them in a different order can matter (and above, certainly does). Even in the reading a file lazily case, if something else in your program writes to the file, then whether you evaluate that list before or after the write action will affect the output of your program, which again, breaks referential transparency (because evaluation order shouldn't matter).
So for a restricted subset of IO actions, you can sensibly define Functor, Applicative and Monad on a stream type to work in a lazy way, but doing so in the IO Monad in general is a minefield and often just plain incorrect. Instead you want a specialised streaming type, and indeed Conduit defines Functor, Applicative and Monad on a lot of it's types so you can still use all your favourite functions.
I'm fairly new to Haskell and have been trying to find a way to pass multiple IO-tainted values to a function to deal with a C library. Most people seem to use the <- operator inside a do block, like this:
g x y = x ++ y
interactiveConcat1 = do {x <- getLine;
y <- getLine;
putStrLn (g x y);
return ()}
This makes me feel like I'm doing C, except emacs can't auto-indent. I tried to write this in a more Lispy style:
interactiveConcat2 = getLine >>= (\x ->
getLine >>= (\y ->
putStrLn (g x y) >>
return () ))
That looks like a mess, and has a string of closed parentheses you have to count at the end (except again, emacs can reliably assist with this task in Lisp, but not in Haskell). Yet another way is to say
import Control.Applicative
interactiveConcat3 = return g <*> getLine <*> getLine >>= putStrLn
which looks pretty neat but isn't part of the base language.
Is there any less laborious notation for peeling values out of the IO taint boxes? Perhaps there is a cleaner way using a lift* or fmap? I hope it isn't too subjective to ask what is considered "idiomatic"?
Also, any tips for making emacs cooperate better than (Haskell Ind) mode would be greatly appreciated. Thanks!
John
Edit: I stumbled across https://wiki.haskell.org/Do_notation_considered_harmful and realized that the nested parentheses in the lambda chain I wrote is not necessary. However it seems the community (and ghc implementors) have embraced the Applicative-inspired style using , <*>, etc, which seems to make the code easier to read in spite of the headaches with figuring out operator precedence.
Note: This post is written in literate Haskell. You can save it as Main.lhs and try it in your GHCi.
A short remark first: you can get rid of the semicolons and the braces in do. Also, putStrLn has type IO (), so you don't need return ():
interactiveConcat1 = do
x <- getLine
y <- getLine
putStrLn $ g x y
We're going to work with IO, so importing Control.Applicative or Control.Monad will come in handy:
> module Main where
> import Control.Applicative
> -- Repeat your definition for completeness
> g :: [a] -> [a] -> [a]
> g = (++)
You're looking for something like this:
> interactiveConcat :: IO ()
> interactiveConcat = magic g getLine getLine >>= putStrLn
What type does magic need? It returns a IO String, takes a function that returns an String and takes usual Strings, and takes two IO Strings:
magic :: (String -> String -> String) -> IO String -> IO String -> IO String
We can probably generalize this type to
> magic :: (a -> b -> c) -> IO a -> IO b -> IO c
A quick hoogle search reveals that there are already two functions with almost that type: liftA2 from Control.Applicative and liftM2 from Control.Monad. They're defined for every Applicative and – in case of liftM2 – Monad. Since IO is an instance of both, you can choose either one:
> magic = liftA2
If you use GHC 7.10 or higher, you can also use <$> and <*> without import and write interactiveConcat as
interactiveConcat = g <$> getLine <*> getLine >>= putStrLn
For completeness, lets add a main so that we can easily check this functionality via runhaskell Main.lhs:
> main :: IO ()
> main = interactiveConcat
A simple check shows that it works as intended:
$ echo "Hello\nWorld" | runhaskell Main.lhs
HelloWorld
References
Applicative in the Typeclassopedia
The section "Some useful monadic functions" of LYAH's chapter "For a Few Monads More".
You can use liftA2 (or liftM2 from Control.Monad):
import Control.Applicative (liftA2)
liftA2 g getLine getLine >>= putStrLn
I often find myself wanting to insert regular functions into a "binded" sequence. Like in this contrived example:
getLine >>= lift (map toUpper) >>= putStrLn
I need to define the lift function lift :: (a -> b) -> a -> m b to make this work. Problem is I don't know of such a function, and Hoogle doesn't seem to either. I find this odd since this makes totally sense to me.
Now, there are probably other ways to make this work, but I like the way point-free style code allows me to scan the line in one pass to figure out what is happening.
let lift f x = return (f x) in
getLine >>= lift (map toUpper) >>= putStrLn
My question boils down to this: am I missing something or how come there isn't a function like lift. My experience in Haskell is still very limited, so I am assuming that most people solve this in a different way. Can someone explain to me the idiomatic way of solving this.
There are three idiomatic ways.
Don't use bind; use the first hit on your Hoogle search instead:
liftM (map toUpper) getLine >>= putStrLn
There are a variety of alternative spellings of liftM, such as fmap or (<$>).
Inline the lift function you defined:
getLine >>= return . map toUpper >>= putStrLn
Use the monad laws to fuse the last two binds in option 2:
getLine >>= putStrLn . map toUpper
Use the Functor instance in such cases:
> import Data.Char
> import Data.Functor
> map toUpper <$> getLine >>= putStrLn
foo
FOO
>