For the "begintermediate" Funk(y-nota)tional Programmer, until more auto-math-ic intuition sets in, a quick-lookup cheat-sheet: examples of the built-in common standard instances for these two foundational Haskell typeclasses (for when GHCi isn't at hand, which it should never be).
A Functor
, to "get mapped over", declares fmap :: (a→b) → (f a) → (f b)
aka. <$>
(this flipped being >~
in my code-bases) with laws:
id <$> foo
≡ id foo
((f <$>).(g <$>)) foo
≡ f.g <$> foo
baz <$ foo
≡ (const baz) <$> foo
An Applicative
(also always a Functor
) "declares a functor with extra laws and operations to enable more/structured functorial
computations". Meaning approximately,
pure
brings a value a
into the functor f
as f a
, and<*>
allows applying some function-in-the-functor f (a->b)
(often a partial application obtained from an earlier <$>
)
to such a value-in-the-functor f a
to obtain the returned such value-in-the-functor f b
.<**>
it not a flip
of <*>
but of some deeper inner $
, ie. "convoluted ×2"*>
discards left-hand side result, <*
same for right-hand but only because:(<* func_in_functor)
is not a flip
of *>
but of the original function encapsulated by
func_in_functor
!All a tad too knotty for my taste, but the basics still need to be understood for comprehending Haskell code-bases. As for the
laws.. similarly labyrinthine,
mostly needed when writing instances (such as on top of a custom Functor
) or for reasoning about existing Applicative-style code.
Given dis = Nothing
and dat = Just "foo"
dis>~reverse
≡ reverse<$> dis
≡ fmap reverse dis
≡ Nothing
dat>~reverse
≡ reverse<$> dat
≡ fmap reverse dat
≡ Just "oof"
"baz" <$ dis
≡ Nothing
"baz" <$ dat
≡ Just "baz"
Further also given cmp = compare <$> dem
where dem = (pure "bar") :: Maybe String
≡ dem = Just "bar"
cmp <*> dis
≡ (here) dis <**> cmp
≡ Nothing
cmp <*> dat
≡ (here) dat <**> cmp
≡ Just LT
cmp *> dis
≡ dis <* cmp
≡ Nothing
cmp *> dat
≡ dat <* cmp
≡ Just "foo"
Just 10 <* Just "20"
≡ Just 10
Just 10 *> Just "20"
≡ Just "20"
Just _ *> Nothing
≡ Nothing *> Just _
≡ Just _ <* Nothing
≡ Nothing <* Just _
≡ Nothing
Given dis = Left "baz"
and dat = Right "foo"
dis>~reverse
≡ reverse<$> dis
≡ fmap reverse dis
≡ Left "baz"
dat>~reverse
≡ reverse<$> dat
≡ fmap reverse dat
≡ Right "oof"
"bar" <$ dis
≡ Left "baz"
"bar" <$ dat
≡ Right "bar"
Further also given cmp = compare <$> dem
where dem = (pure "bar") :: Either String String
≡ dem = Right "bar"
cmp <*> dis
≡ (here) dis <**> cmp
≡ Left "baz"
cmp <*> dat
≡ (here) dat <**> cmp
≡ Right LT
cmp *> dis
≡ dis <* cmp
≡ Left "baz"
cmp *> dat
≡ dat <* cmp
≡ Right "foo"
Right 10 <* Right "20"
≡ Right 10
Right 10 *> Right "20"
≡ Right "20"
Left anything *> _
≡ _ *> Left anything
≡ Left anything <* _
≡ _ <* Left anything
≡ Left anything
Given disndat = ("baz","foo")
disndat>~reverse
≡ reverse<$> disndat
≡ fmap reverse disndat
≡ ("baz","oof")
"bar" <$ disndat
≡ ("baz","bar")
Further also given cmp = compare <$> dem
where dem = (pure "bar") :: (String,String)
≡ dem = ("","bar")
cmp <*> disndat
≡ (here) disndat <**> cmp
≡ ("baz",LT)
cmp *> disndat
≡ disndat <* cmp
≡ ("baz","foo")
("a",'b') <* ("c",'d')
≡ ("ac",'b')
("a",'b') *> ("c",'d')
≡ ("ac",'d')
(GT,True) <* (LT,False)
≡ (GT,True)
(GT,True) *> (LT,False)
≡ (GT,False)
Given dis = []
and dat = ["foo","baz"]
dis>~reverse
≡ reverse<$> dis
≡ fmap reverse dis
≡ []
dat>~reverse
≡ reverse<$> dat
≡ fmap reverse dat
≡ ["oof","zab"]
"bar" <$ dis
≡ []
"bar" <$ dat
≡ ["bar","bar"]
Further also given cmp = compare <$> dem
where dem = (pure "dem") :: [String]
≡ dem = ["dem"]
cmp <*> dis
≡ (here) dis <**> cmp
≡ []
cmp <*> dat
≡ (here) dat <**> cmp
≡ [LT,GT]
cmp *> dis
≡ dis <* cmp
≡ []
cmp *> dat
≡ dat <* cmp
≡ ["foo","baz"]
[1,2] <* [3,4]
≡ [1,1,2,2]
[1,2] <* [3,4,5]
≡ [1,1,1,2,2,2]
[1,2] <* [3,4,5,6]
≡ [1,1,1,1,2,2,2,2]
[1,2,3,4] *> [5,6]
≡ [5,6,5,6,5,6,5,6]
"yo" *> "foo"
≡ "foofoo"
"yo" <* "fee"
≡ "yyyooo"
"zoom" *> "ya"
≡ "yayayaya"
"zoom" <* "ya"
≡ "zzoooomm"
[] *> _
≡ _ *> []
≡ [] <* _
≡ _ <* []
≡ []
[reverse , id] <*> ["foo","bar"]
≡ ["oof","rab","foo","bar"]
Given dat = (pure "foo") :: IO String
dat>~reverse
≡ reverse<$> dat
≡ fmap reverse dat
≡ dat >>= (pure . reverse)
≡
(pure "oof") :: IO String
"baz" <$ dat
≡ (pure "baz") :: IO String
Further also given dis = (pure "") :: IO String
and cmp = compare <$> dem
where dem = (pure "dem") :: IO String
cmp <*> dis
≡ (here) dis <**> cmp
≡ (pure GT) :: IO Ordering
cmp <*> dat
≡ (here) dat <**> cmp
≡ (pure LT) :: IO Ordering
cmp *> dis
≡ dis <* cmp
≡ (pure "") :: IO String
cmp *> dat
≡ dat <* cmp
≡ (pure "foo") :: IO String
dis *> dat
≡ dat <* dis
≡ (pure "foo") :: IO String
dat *> dis
≡ dis <* dat
≡ (pure "") :: IO String
Given dat = "foo-bar"
and dis = [1,2,3,4]
or []
or [True]
or any other list..
(tail>~reverse) dat
≡ (reverse <$> tail) dat
≡ (fmap reverse tail) dat
≡ (reverse . tail) dat
≡ (tail~.reverse) dat
≡ "rab-oo"
(reverse>~tail) dat
≡ (tail <$> reverse) dat
≡ (fmap tail reverse) dat
≡ (tail . reverse) dat
≡ (reverse~.tail) dat
≡ "ab-oof"
(reverse>~head) dat
≡ (head <$> reverse) dat
≡ (fmap head reverse) dat
≡ (head . reverse) dat
≡ (reverse~.head) dat
≡ 'r'
(tail <$ head) dis dat
≡ tail dat
≡ "oo-bar"
(head <$ tail) dis dat
≡ head dat
≡ 'f'
Really not ready to go there..