如何减少/简化此代码(或通常具有多个输入的代码)?
do
sex <- askSex
name <- askName
sayHello sex name
在这种情况下已经非常短,但是当它进入多个输入时,它看起来很混乱。有没有办法做这样的事情:
sayHello askSex askName
答案 0 :(得分:5)
如果你
import Control.Applicative -- for <$> and <*>
import Control.Monad -- for join
你可以写
join $ sayHello <$> askSex <*> askName
对于您的示例,您只获取两个参数,这不是一个大赢家。但是对于更多的参数,它可以使代码更清晰。
join $ doSomething <$> getFirst <*> getSecond <*> getThird <*> getForth
答案 1 :(得分:3)
这是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
它在今天我给你的答案中有点像fmap
,但对于大量的论点,就像你在这里一样。
使用像我的hello
这样的函数和applicative functor可以帮助您将IO代码与其余代码分开,这是非常好的做法。每次尝试写hello
而不是sayHello
。
答案 2 :(得分:1)
令人讨厌的是,hoogle没有一个简单的答案。这将被称为bind2
。如果它只是一个输入的函数,那么您可以使用=<<
,即我称之为bind1
的中缀版本。
sayHello =<< askName
但对于多种输入,我们运气不好。无论出于何种原因,标准库都没有提供:
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
当然,您可以自己定义它。