简化嵌套模式匹配



我的代码中有以下结构:

f :: Maybe A -> X
f a = case a of
  Nothing -> x
  (Just b) -> case b of
    Nothing -> y
    (Just c) -> case c of
      Nothing -> z
      (Just d) -> d

我没有看到一种明显的方法来简化它,而不是使用嵌套的maybe函数,这不会让整个事情看起来更好。是否有任何聪明但仍然可以理解的技巧可以帮助使这种结构更加"优雅"?

为什么代码首先构造一个Maybe (Maybe (Maybe X))值?解开这样的价值并不好,但真正的问题是,为什么会有这样的价值。也许代码会更好地避免所有这些嵌套的 Maybes。

如果你真的需要有这样的值,并且需要在所有Just/Nothing的情况下做不同的事情,你必须把它们都写下来。但是,您可以将它们组合成一个大的模式匹配,而不是几个嵌套的case语句:

f Nothing                = x
f (Just Nothing))        = y
f (Just (Just Nothing))  = z 
f (Just (Just (Just d))) = d

尽管您对不使用maybe的限制,我认为这看起来不错:

f = maybe x (maybe y (maybe z id))

甚至更好,正如@pat在他的评论中所建议的那样:

f = maybe x . maybe y . maybe z $ id

更新 2

Monad Either适合您

import Data.Maybe (maybe)
maybeE :: e -> Maybe a -> Either e a
maybeE e = maybe (Left e) Right
f :: Maybe (Maybe (Maybe d)) -> Either e d
f a  =   maybeE x a 
     >>= maybeE y
     >>= maybeE z

已更新 3

如果我们想没有Either类型,我们可以重写函数:

import Data.Either(either)
either' = either id id
f :: Maybe (Maybe (Maybe d)) -> d
f a = either' $ maybeE x a 
            >>= maybeE y
            >>= maybeE z

最新更新