【问题标题】:Haskell maps returning a monadHaskell 映射返回一个单子
【发布时间】:2011-03-03 03:02:00
【问题描述】:

Data.Map 和 Data.IntMap 中的查找函数当前返回用 Maybe 包装的值 类型签名

lookup  :: Ord  k => k -> Map  k a -> Maybe  a

它曾经有更通用的类型

lookup  :: (Monad  m, Ord  k) => k -> Map  k a -> m a

我意识到前者可能会减少对额外类型规范的需求,但后者会使其更加通用并允许在列表推导中使用查找。有没有办法用新版本来模仿这种行为,还是我必须使用旧版本的库?

【问题讨论】:

    标签: haskell map monads maybe


    【解决方案1】:

    后者会使其更通用,并允许在列表推导中使用查找

    后者也更不安全,因为大多数 monad 类将失败定义为error。也就是说,在 Map 中找不到元素的常见情况是大多数 monad 的程序终止错误。再加上推断错误类型上下文的可能性增加,这意味着我们现在倾向于不鼓励“单子失败返回”样式。

    有没有办法用新版本来模仿这种行为

    确实有!只需将 Maybe a 提升到 Monad a 中,如下所示:

    lift :: Monad m => Maybe a -> m a
    lift Nothing  = fail "you die now"
    lift (Just a) = return a
    

    现在你可以写了,例如lift . lookup

    【讨论】:

    • 感谢唐的快速回复。这比我想出的要简洁得多。
    • 一旦base 的下一个主要版本出现,考虑更新这个答案可能是有意义的。看起来fail 终于要离开Monad,也许会登陆一个新的MonadFail
    【解决方案2】:

    Don 的liftMaybe 的元素转换为它们一般的Monad 对应物,所以也许应该将其命名为convertgeneralize 之类的;-)

    如果您只想在列表推导和其他实现fail 的单子中主要使用lookup,您还可以使用模式匹配失败到fail 的映射:

    前奏> [ v |只需 v [ v |只需 v do Just v :1:3-8 处的 do 表达式中的模式匹配失败) Prelude> do Just v

    【讨论】:

    • 这完美地说明了为什么使用失败是不好的:它几乎总是一个程序终止异常。不是您在地图中查找时想要的。
    • 好吧,我说的是“实现失败的单子”,不是吗?-) error 未定义未实现。我也只是想说明这种情况。就个人而言,当 monad 也是 MonadPlus 并将 fail 实现为 mzero 时,我在 do-blocks 中使用模式匹配失败。这就是这种技术最有用的时候。
    【解决方案3】:

    对于list monad的具体情况,最简单的解决方案是使用maybeToList

    Prelude> :m +Data.Maybe -- Note: Use "import Data.Maybe" in a program file
    
    Data.Maybe> [ v | v <- maybeToList $ lookup "hi" [("ho","silver")] ]
    []
    Data.Maybe> [ v | v <- maybeToList $ lookup "ho" [("ho","silver")] ]
    ["silver"]
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-17
      • 1970-01-01
      • 2018-11-21
      • 1970-01-01
      • 2019-10-31
      相关资源
      最近更新 更多