Haskell打印并使用monad中的值

时间:2016-11-09 21:55:37

标签: haskell

所以,我尝试做的是在使用之前打印两个值。这里有两种完美的工作方式,但我觉得还有其他方法可以做到。我知道这样做的建议方法很可能就是阻止,因为它的布局是最简单的,但为什么不看其他呢?

-- 1
main = do
    a <- m1
    b <- m2
    print a
    print b
    print $ f a b

-- 2
p x = print x >> return x

main = print =<< liftM2 f (p =<< m1) (p =<< m2)

我也试过这些,但是他们遇到了问题,我们无法弄明白,而且似乎没有合适的东西连在一起。

main = print =<< foldl1 f . mapM p =<< sequence [m1, m2]
main = print =<< on f p m1 m2
main = print . curry (on f) =<< (uncurry (join (***)) p) m1 m2

我认为来自Data.Function的on非常接近我想做的事情,但我不知道如何管理两个monadic值。提前感谢任何建议。

编辑:第一个问题有点宽泛:如何重写第一个do块?我的另一个问题是如何从monad中提取两个值到一个带两个值的函数? 如果某个函数执行(m a, m a) -> m (a, a)之类的操作,那么我认为可以curry (on f p) =<< thatfunction (m1, m2),但可能有另一种方式。

2 个答案:

答案 0 :(得分:1)

如果你想让事情变得更短,你可以创建一些执行打印的Applicative式组合器:

import Control.Monad.IO.Class (MonadIO(..))

(<*&>) :: (MonadIO m, Show a) => m (a -> b) -> m a -> m b
mf <*&> mx = do
  f <- mf
  x <- mx
  liftIO $ print x
  return $ f x

(<$&>) :: (MonadIO m, Show a) => (a -> b) -> m a -> m b
f <$&> mx = pure f <*&> mx

(名字可能会留下一些不足之处,但我会把它留给你。)

使用这些运算符,您可以像这样编写原始示例:

main = print $ f <$&> m1 <*&> m2

您是否认为这更清楚取决于您(可能取决于您使用此模式的频率)。

答案 1 :(得分:0)

你可能想要这个:

main = (liftM2 f `on` (>>= p)) m1 m2 >>= print
       where f = (++)
             p x = print x >> return x
             m1 = getLine
             m2 = getLine
  • liftM2 f创建f版本,其“参数”均为monadic值。
  • on创建一个函数,将“参数”传递到(>>= p),然后再传递给liftM2 f
  • 然后将最终结果绑定到print

结果,这个例子

  1. 等待输入一行,然后打印该行
  2. 等待输入另一行,然后打印
  3. 连接两行然后打印结果。