如果模式与“可能是”结果匹配

If pattern matching with `Maybe a` result

以下代码说明了我的意图。我想模式匹配,如果不匹配结果是Nothing,如果匹配结果是Just something

data MyData = 
      A Int
    | B String
    | C


ifA (A i) = Just i 
ifA _     = Nothing

ifB (B str) = Just str
ifB _     = Nothing

ifC C = Just () 
ifC _ = Nothing 



mbMult3 i = Just (i*3)

concWorld str = Just (str ++ "World")

example1 v = ifA v >>= mbMult3

example2 v = ifB v >>= concWorld

-- example2 (B "Hello ,") == Just "Hello, World"
-- example2 (A 3) == Nothing

还有其他方法吗ifAifBifC

编辑:

  1. 我怀疑 lens 图书馆可能有一些东西。但是我现在对lens一无所知。
  2. 已更新ifC

Prisms from the lens package model this. You can generate prisms for your type using makePrisms, then use ^? (or its prefix equivalent, preview) 访问 sum 类型的成员,如果提供了不同的值,则生成 Nothing

{-# LANGUAGE TemplateHaskell #-}

import Control.Lens

data MyData
  = A Int
  | B String
  | C
  deriving (Show)

makePrisms ''MyData
ghci> A 42 ^? _A
Just 42
ghci> A 42 ^? _B
Nothing
ghci> C ^? _C
Just ()

棱镜的好处在于它们可以与其他光学器件组合(例如 lenses, folds, and traversals),以及使用它们通过组合棱镜来遍历嵌套的求和类型:

ghci> (A 42, C) ^? _1._A
Just 42
ghci> (B "hello", C) ^? _1._A
Nothing
ghci> Just (A 42) ^? _Just._A
Just 42
ghci> Just (B "hello") ^? _Just._A
Nothing
ghci> Nothing ^? _Just._A
Nothing

lens 包相当复杂,解释它的所有功能完全超出了这个答案的范围。如果您不需要太多,您的解决方案可能没问题。但是,如果您发现自己经常编写此类代码,那么镜头可能会有所帮助,只要您愿意接受陡峭的学习曲线和经常令人困惑的类型错误。


† 更一般地说,^? 适用于任何产生零值或一个值(或更多,它只忽略除第一个值以外的所有值)的 Fold,但棱镜是专为求和类型而设计,因此它们在这里更相关。

这是我不时使用的一个可爱的成语,因为我还没有戴上镜头。

{-# LANGUAGE MonadComprehensions #-}

example1 v = [ x | A x <- pure v ] >>= mbMult3