【问题标题】:Is there any way to "lift" a constructor?有没有办法“提升”构造函数?
【发布时间】:2019-03-20 13:09:18
【问题描述】:

假设我有一个只接受并返回Int 的函数(在下面的示例中为plusOne)。但我没有Int;相反,我有一个Maybe Int;如果这个Maybe Int 包含一个值,那么我想将它传递给plusOne 并得到plusOne 返回的Just,或者如果它是Nothing,那么我希望这个Nothing 传播。

在这种情况下,我们有 liftM 以优雅的方式编写代码:

import Control.Monad

plusOne :: Int -> Int
plusOne n =
    n+1 -- a very complicated computation that is failsafe

main =
    let n = Just 15 -- a very complicated computation that can fail
    in let res = liftM plusOne n
    in print res

到目前为止一切顺利。但是,这样的事情也可以用构造函数来完成吗?

忘记plusOne。现在我有:data SomeData = SomeData Int 并想从我的Maybe Int 获得一个Maybe (SomeData Int)。该解决方案似乎明显不那么优雅:

import Control.Monad

data SomeData = SomeData Int
    deriving Show -- so that print works

main =
    let n = Just 15
    in let res = n >>= (\nn -> Just (SomeData nn))
    -- alternatively: in let res = liftM (\nn -> SomeData nn) n
    in print res

上述两种解决方案(使用>>=liftM)都需要通过一个匿名 lambda 函数,根据我的直觉,这不是必需的,只会破坏代码。有没有办法避免它?我可以像在第一个 sn-p 中提升 plusOne 一样以某种方式“提升”someData 构造函数吗?

【问题讨论】:

  • \nn -> Just (SomeData nn) 只是Just . SomeData
  • let res = liftM (\nn -> SomeData nn)liftM SomeData 相同。 (或者确实是fmap SomeData - 这是个人选择,但我更喜欢调用函数fmap。)
  • 现在无法编辑,但我显然是指上面的“与let res = liftM SomeData相同”
  • @RobinZigmond 哇,谢谢!不知道构造函数算作函数。

标签: haskell constructor monads maybe lifting


【解决方案1】:

你可以简单地使用函数组合:

main =
    let n = Just 15
        res = n >>= Just . SomeData
    in print res

尽管正如 Robin Zigmond 指出的那样,您可以简单地使用 fmap,因为 fmap f x 相当于 x >>= return . f,而 return == Just 相当于 Maybe monad。

main = let n = Just 15
           res = fmap SomeData n  -- or SomeData <$> n
       in print res

故事的寓意:不要使用只需要函子的 monad。

【讨论】:

  • 所以现在你提示我检查 fmap 是什么干草 :) Dang 我对 Haskell 知之甚少,但受人尊敬的学院希望我在没有两个多月的语言介绍。
  • 我也不知道函子是什么 ;P 虽然在其中一堂课中略过,可惜我没有太注意。我刚刚开始了解 monad 的基础知识,这就是我的所在。
  • 要么你上课不专心,要么你的班级做事极度倒退。在被介绍给 monad 之前,您应该已经学习了仿函数 long(因为每个 monad 一个仿函数,无论是在数学定义还是在 Haskell 中,因为 Functor 实例是必需的每个类型都定义了一个 Monad 实例)。
  • 完全同意@chepner 的观点,你似乎学习的方式是倒退的。如果您需要相对快速且轻松地介绍这些概念,我强烈推荐Learn You a Haskell - 特别是在第 11 章和第 12 章的上下文中。
  • @gaazkam fmapliftM 完全相同,只是 fmapliftM 工作的类型(非常)少。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-11
  • 2021-11-11
  • 2011-07-28
  • 1970-01-01
  • 1970-01-01
  • 2011-10-08
相关资源
最近更新 更多