2

如何可以减少/简化此代码(或一般而言,具有多个输入的代码)?

do
  sex    <- askSex
  name   <- askName
  sayHello sex name

在这种情况下已经很短了,但是当它到达多个输入时,它看起来很乱。有没有办法做类似的事情:

sayHello askSex askName

?

4

3 回答 3

5

如果你

import Control.Applicative  -- for <$> and <*>
import Control.Monad        -- for join

你可以写

join $ sayHello <$> askSex <*> askName

对于您的示例,您只获取两个参数,这不是一个很大的胜利。但是对于更多数量的参数,它可以使代码更清晰。

join $ doSomething <$> getFirst <*> getSecond <*> getThird <*> getForth
于 2013-01-09T17:58:11.137 回答
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与应用函子一起使用可以帮助您将 IO 代码与其他代码分开,这是非常好的做法。试着写hello而不是sayHello每次。

于 2013-01-09T18:10:10.310 回答
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

当然,您可以自己定义。

于 2013-01-10T16:12:11.240 回答