Home > Software engineering >  Is there a nice way to unwrap a Maybe value that is inside of a tuple?
Is there a nice way to unwrap a Maybe value that is inside of a tuple?

Time:10-23

The signature I'm looking for is (Maybe a, b) -> (a, b), which hoogle returns no results for. I can easily write my own as

import Data.Maybe (fromJust)

fromJustTuple :: (Maybe a, b) -> (a, b)
fromJustTuple (a, b) = (fromJust a, b)

The context is that I'm using updateLookupWithKey on a Map where I can guarantee that the keys I'm querying exist. I could say

let (Just x, myMap') = updateLookupWithKey f k myMap

, but then I'd have to disable incomplete-uni-patterns, which I don't want to do.

Backing up a bit, this may be an XY problem. I'm happy to hear so and learn about a different, more idiomatic approach.

CodePudding user response:

Copying my own comments into an answer:

You could write fromJustTuple as first fromJust (where first is from Control.Arrow).

first has the type signature:

first :: Arrow a => a b c -> a (b, d) (c, d) 

But it probably makes sense for you to ignore the "arrow" part of first, and pretend it was specialized to functions, which gives it the type:

first :: (b -> c) -> (b, d) -> (c, d)

That is: it maps over the first element of a tuple.


Ultimately, I think your problem is that although you "can guarantee that the keys [you're] querying exist", you can't prove this to the type system, so unless you can change this, you're going to have to rely on unsafe functions like fromJust, or get incomplete pattern match warnings.

CodePudding user response:

I think the cause of the difficulty is that updateLookupWithKey is just not the right tool. Why not use alterF?

import Data.Map (Map)
import qualified Data.Map as M

import Data.Maybe

update :: (Ord k, Num a) => (a -> a) -> k -> Map k a -> (a, Map k a)
update f = M.alterF (\old -> let new = f (fromMaybe 0 old) in (new, Just new))

incr :: (Ord k, Num a) => k -> Map k a -> (a, Map k a)
incr = update ( 1)

decr :: (Ord k, Num a) => k -> Map k a -> (a, Map k a)
decr = update (subtract 1)

Now the only appearance of Maybe is to cover when the key is actually absent from the Map, and it defaults the associated value to 0 in that case.

  • Related