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?

``````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`