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.