Unwrapping datatypes in Haskell without extraneous code

前端 未结 3 1334
臣服心动
臣服心动 2021-01-11 12:21

Say I have

x = Just 2

Is there a way (preferrably a builtin mechanism/function) to use x in a single statement such that if it is a Just, t

相关标签:
3条回答
  • 2021-01-11 13:13

    fromJust should do what you want.

    0 讨论(0)
  • 2021-01-11 13:18

    For this particular case, fromJust. In general

    let Just k = x in f k + 2 == 4
    

    This trick works with any datatype constructor and is very commonly used with (:) for nonempty lists.

    0 讨论(0)
  • 2021-01-11 13:21

    Data.Maybe.fromJust has been mentioned by other answers already:

    fromJust :: Maybe a -> a
    fromJust Nothing  = error "Maybe.fromJust: Nothing"
    fromJust (Just x) = x
    

    There's also maybe (found in both Prelude and Data.Maybe):

    maybe :: b -> (a -> b) -> Maybe a -> b
    maybe n _ Nothing  = n
    maybe _ f (Just x) = f x
    

    fromJust can be written using maybe:

    fromJust = maybe (error "Maybe.fromJust: Nothing") id
    

    As you can see, maybe allows you flexibility in handling both cases without requiring pattern matching:

    \x -> maybe 0 (+ 2) x  -- Nothing -> 0, Just 2 -> 4
    

    Similarly, Prelude and Data.Either have either :: (a -> c) -> (b -> c) -> Either a b -> c:

    \x -> either (subtract 1) (* 2) x  -- Left 5 -> 4, Right 3 -> 6
    

    If you define a data type

    data MyDataType
      = TypeA { foo :: Int, bar :: String }
      | TypeB { foo :: Int,                baz :: () }
      | TypeC {             bar :: String, baz :: () }
    

    like this, you end up with partial functions for accessors.

    foo :: MyDataType -> Int
    bar :: MyDataType -> String
    baz :: MyDataType -> ()
    

    They're called partial functions, as opposed to total functions, because they only return results for a subset of their inputs.

    foo (TypeA { foo = 15, bar = "hello!" })  -- 15
    bar (TypeB { foo = 12345679, baz = () })  -- error
    
    0 讨论(0)
提交回复
热议问题