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.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.