I have a function that looks like this:
import Data.Bifunctor (lmap)
import Data.Int (fromString)
keyToInt :: forall a. Tuple String a -> Tuple (Maybe Int) a
keyToInt = lmap fromString
What I'd like is this type signature:
keyToInt :: forall a. Tuple String a -> Maybe (Tuple Int a)
This seems to work:
keyToInt :: forall a. Tuple String a -> Maybe (Tuple Int a)
keyToInt tuple = extractFstMaybe $ lmap fromString tuple
where
extractFstMaybe :: forall a. Tuple (Maybe Int) a -> Maybe (Tuple Int a)
extractFstMaybe (Tuple (Just a) b) = Just $ Tuple a b
extractFstMaybe (Tuple Nothing _) = Nothing
But it feels like there should be a more abstract/cleaner way to express this. If I were to take extractMaybe to it's natural conclusion, I might create something like
-- The typing doesn't really work for this
extractMaybe :: forall a b c d. (Tuple a b) -> Maybe (Tuple c d)
extractMaybe (Tuple (Just a) (Just b)) = Just $ Tuple a b
extractMaybe (Tuple (Just a) b) = Just $ Tuple a b
extractMaybe (Tuple a (Just b)) = Just $ Tuple a b
extractMaybe (Tuple Nothing _) = Nothing
extractMaybe (Tuple _ Nothing) = Nothing
extractMaybe (Tuple a b) = Just $ Tuple a b
While reading about applicatives and bind, this is the sort of refactoring I would see a lot. I don't really have the experience yet to apply those lessons for myself.
If I have a structure that may contain an ADT (An Array of Eithers, or Maybes, or Arrays) and I want to define a way pulling those "out," is there a generalized way to define that?
Purescript by Example has an example with this type signature for a function:
combineList :: forall f a. Applicative f => List (f a) -> f (List a)
which is doing the same thing, only for a List. N-Tuples complicate this because every element can have a different type. If I call extractMaybe on a Tuple, I now a have a Tuple with any types except for Maybe (or I have Nothing).
I could write the same thing for Either and if I use both, I could know I have a Tuple with any types except for Maybe and Either (or I have Nothing).
I'm not even entirely sure this is the most helpful direction to go in. It seems helpful in situations like mapMaybe where you want to filter out all Nothings and Lefts while unwrapping those types as well.
extractFstMaybecan be written more abstractly/cleanly. The section of Purescript by Example that you link to is aboutTraversable, and sinceMaybeisApplicativeandTuple aisTraversable,sequencecan be specialised to the typeforall a b. Tuple a (Maybe b) -> Maybe (Tuple a b). That's not quite what you want, because it "extracts" the wrong element of the tuple - but (TBC)... - Robin ZigmondextractFstMaybe = map swap . sequence . swap- Robin Zigmondswap >>> sequence >>> map swapand that somehow clicked - Mrk Sef