Created
March 27, 2021 07:40
-
-
Save hyperrealgopher/fbaa716cb3d34be3e5bd882aba0ea603 to your computer and use it in GitHub Desktop.
system-f/fp-course: Optional.hs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{-# LANGUAGE NoImplicitPrelude #-} | |
{-# LANGUAGE ScopedTypeVariables #-} | |
module Course.Optional where | |
import qualified Control.Applicative as A | |
import qualified Control.Monad as M | |
import Course.Core | |
import qualified Prelude as P | |
-- | The `Optional` data type contains 0 or 1 value. | |
-- | |
-- It might be thought of as a list, with a maximum length of one. | |
data Optional a = | |
Full a | |
| Empty | |
deriving (Eq, Show) | |
-- | Map the given function on the possible value. | |
-- | |
-- >>> mapOptional (+1) Empty | |
-- Empty | |
-- | |
-- >>> mapOptional (+1) (Full 8) | |
-- Full 9 | |
mapOptional :: | |
(a -> b) | |
-> Optional a | |
-> Optional b | |
mapOptional f (Full a) = Full (f a) | |
mapOptional _ Empty = Empty | |
-- | Bind the given function on the possible value. | |
-- | |
-- >>> bindOptional Full Empty | |
-- Empty | |
-- | |
-- >>> bindOptional (\n -> if even n then Full (n - 1) else Full (n + 1)) (Full 8) | |
-- Full 7 | |
-- | |
-- >>> bindOptional (\n -> if even n then Full (n - 1) else Full (n + 1)) (Full 9) | |
-- Full 10 | |
bindOptional :: | |
(a -> Optional b) | |
-> Optional a | |
-> Optional b | |
bindOptional f (Full a) = f a | |
bindOptional _ Empty = Empty | |
-- | Return the possible value if it exists; otherwise, the second argument. | |
-- | |
-- >>> Full 8 ?? 99 | |
-- 8 | |
-- | |
-- >>> Empty ?? 99 | |
-- 99 | |
(??) :: | |
Optional a | |
-> a | |
-> a | |
(Full a) ?? _ = a | |
Empty ?? x = x | |
-- | Try the first optional for a value. If it has a value, use it; otherwise, | |
-- use the second value. | |
-- | |
-- >>> Full 8 <+> Empty | |
-- Full 8 | |
-- | |
-- >>> Full 8 <+> Full 9 | |
-- Full 8 | |
-- | |
-- >>> Empty <+> Full 9 | |
-- Full 9 | |
-- | |
-- >>> Empty <+> Empty | |
-- Empty | |
(<+>) :: | |
Optional a | |
-> Optional a | |
-> Optional a | |
Empty <+> x = x | |
x <+> Empty = x | |
x <+> _ = x | |
-- | Replaces the Full and Empty constructors in an optional. | |
-- | |
-- >>> optional (+1) 0 (Full 8) | |
-- 9 | |
-- | |
-- >>> optional (+1) 0 Empty | |
-- 0 | |
optional :: | |
(a -> b) | |
-> b | |
-> Optional a | |
-> b | |
optional f _ (Full a) = f a | |
optional _ d Empty = d | |
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 | |
contains :: Eq a => a -> Optional a -> Bool | |
contains _ Empty = False | |
contains a (Full z) = a == z | |
instance P.Functor Optional where | |
fmap = | |
M.liftM | |
instance A.Applicative Optional where | |
(<*>) = | |
M.ap | |
pure = | |
Full | |
instance P.Monad Optional where | |
(>>=) = | |
flip bindOptional | |
return = | |
Full |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment