【问题标题】:Understanding liftM2 in haskell了解haskell中的liftM2
【发布时间】:2017-05-04 11:27:51
【问题描述】:

我很难理解 liftM2 在 haskell 中的工作原理。 我写了以下代码,但它没有输出任何东西。

import Control.Monad
main = liftM2 (\a b -> putStrLn$show$(+) a b) readLn readLn 

【问题讨论】:

    标签: haskell io


    【解决方案1】:

    liftM2的类型开始会有所帮助:

    liftM2 :: Monad m => (a1 -> a2 -> r) -> m a1 -> m a2 -> m r
    

    第一个参数是 2 个参数的函数,例如 (+)。通常,您会像这样使用(+)

    > 3 + 5
    8
    

    但是,您没有两个 Num a => a 类型的值;您正在使用readLn :: Read a => IO a 获取Num a => IO a 类型的值。如果您尝试直接添加这些值:

    :t (+) readLn readLn
    (+) readLn readLn :: (Read a, Num (IO a)) => IO a
    

    它需要IO a 才能拥有Num 实例。也就是说,您不想添加readLn 的返回值;您想在这些返回值中添加数字 wrapped。你可以明确地这样做:

    do
     x <- readLn
     y <- readLn
     return $ x + y
    

    或者,您可以“修改”(+) 以隐式解包参数,然后将结果打包。这就是 liftM2 所做的:它接受一个 2 参数函数,并将其“提升”到 monad 中,以便它可以处理包装的值。

    > :t (+)
    (+) :: Num a => a -> a -> a
    > :t liftM2 (+)
    liftM2 (+) :: (Num r, Monad m) => m r -> m r -> m r
    

    所以虽然(+) 3 5 :: Num a =&gt; aliftM2 (+) $ (return 3) (return 5) :: (Monad m, Num a) =&gt; m a。前者计算为8,后者计算为return 8(无论return 对特定的monad 做什么)。一些非IO 的例子:

    > (liftM2 (+)) (Just 3) (Just 5)
    Just 8
    > (liftM2 (+)) [3] [5]
    [8]
    > (liftM2 (+)) (Right 3) (Right 5)
    Right 8
    

    liftM2map 非常相似;事实上,liftM(提升 1-argument 函数的版本)只是 map 的另一个名称。

    【讨论】:

    • 虽然我想我能理解你想要解释的内容,但我认为你的 liftM2 (+) $ (IO 3) (IO 5) == IO 8 行可能会产生误导。
    • 什么,仅仅因为IO 3IO 5 实际上不是有效的Haskell 表达式? :)
    • 我认为我的改变是一种进步。
    【解决方案2】:

    我不认为编译器可以在 $ 周围没有空格的情况下解析它。然后,这里 main 的类型为 IO (IO ())

    如果要对“内部”IO求和,可以使用liftM2 (+),然后打印结果。

    例如:

    main :: IO ()
    main = print =<< liftM2 (+) readLn readLn
    

    或者使用 do 表示法:

    main :: IO ()
    main = do
      s <- liftM2 (+) readLn readLn
      print s
    

    【讨论】:

    • 好的,那么我们如何使用liftM2 读取两个整数并打印它们的总和?
    • $ 没有空格只有在-XTemplateHaskell 处于活动状态时才会出现问题。但是,是的,总是在它周围留出空间可能是个好主意,这样你就不必担心它,以防你以后需要使用 TH。 $ 无论如何都是一个非常“空间”的运算符,它的优先级很低。
    猜你喜欢
    • 1970-01-01
    • 2011-04-28
    • 1970-01-01
    • 2016-01-31
    • 2019-02-02
    • 1970-01-01
    • 1970-01-01
    • 2016-06-01
    • 1970-01-01
    相关资源
    最近更新 更多