DEV Community

Anton
Anton

Posted on

I can't understand the twiceOptional function from Data61 fp course.

-- Here's what we've got with Optional

data Optional a
  = Full a
  | Empty
  deriving Show (Eq, Show)

mapOptional :: (a -> b) -> Optinoal a -> Optional b
mapOptional _ Empty = Empty
mapOptional f (Full a) = Full (f a)

bindOptional :: (a -> Optional b) -> Optional a -> Optional b
bindOptional _ Empty = Empty
bindOptional f (Full a) = f a

applyOptional :: Optional (a -> b) -> Optional a -> Optional b
applyOptional f a = bindOptional (\f' -> mapOptional f' a) f

twiceOptional :: (a -> b -> c) -> Optional a -> Optional b -> Optional c
twiceOptional f = applyOptional . mapOptional f


-- | Convert a list of optional values to an optional list of values.
--
-- * If the list contains all `Full` values, 
-- then return `Full` list of values.
--
-- * If the list contains one or more `Empty` values,
-- then return `Empty`.
--
-- * The only time `Empty` is returned is
-- when the list contains one or more `Empty` values.
--
-- >>> seqOptional (Full 1 :. Full 10 :. Nil)
-- Full [1,10]
--
-- >>> seqOptional Nil
-- Full []
--
-- >>> seqOptional (Full 1 :. Full 10 :. Empty :. Nil)
-- Empty
--
-- >>> seqOptional (Empty :. map Full infinity)
-- Empty
seqOptional ::
  List (Optional a)
  -> Optional (List a)
seqOptional =
  foldRight (twiceOptional (:.)) (Full Nil)

Things I don't understand:

  1. We are passing three arguments to the twice function.
twiceOptional :: (a -> b -> c) -> Optional a -> Optional b -> Optional c
twiceOptional f = applyOptional . mapOptional f

mapOptional on the other hand takes only two arguments. Why mapOptional doesn't get angry? The partial application here works like this:

twiceOptional (+) (Full 1) (Full 2) = applyOptional . mapOptional f (Full 1) (Full 2)

2.

>>> seqOptional (Empty :. map Full infinity)
Empty

seqOptional shows that it will stop execution when it encounters the first Empty value. Why it stops execution?

P.S. the link to the course itself

Top comments (1)

Collapse
 
jvanbruegge profile image
Jan van Brügge
  1. You are wrong about the partial application, it is like this (note the parenthesis):
twiceOptional (+) (Full 1) (Full 2) = (applyOptional . mapOptional (+)) (Full 1) (Full 2)
  1. Because when bindOptional encounters an Empty it does not evaluate further and just returns Empty