Last active
November 19, 2018 08:35
-
-
Save Woody88/ffc6386794cf3a866e6aab13c9adcd45 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
| module Reader1 where | |
| data Reader r a = Reader { runReader :: r -> a } | |
| instance Functor (Reader r) where | |
| -- fmap :: (a -> b) -> Reader r a -> Reader r b | |
| -- fmap :: (a -> b) -> (r -> a) -> (r -> b) | |
| -- I can compose the body | |
| -- fmap f (Reader ra) = Reader $ \r -> f (ra r) | |
| fmap f (Reader ra) = Reader $ f . ra | |
| instance Applicative (Reader r) where | |
| {-- pure :: a -> Reader r a | |
| pure :: a -> (r -> a) | |
| very similar to the const type definition. It also makes sense that the const function | |
| should work. The purpose of the reader function is to never modify the r value. const never | |
| touches the second argument. | |
| const :: a -> b -> a | |
| const :: a -> (r -> a) -- same as pure function | |
| pure x = Reader $ \r -> x -- original function | |
| --} | |
| pure = Reader . const | |
| {-- (<*>) :: Reader r (a -> b) -> Reader r a -> Reader r b | |
| (<*>) :: r -> (a -> b) -> (r -> a) -> (r -> b) | |
| I can use applicative for the body | |
| f :: r -> a -> b | |
| ra :: r -> a | |
| both need a reader, hence applicative is what we are looking for. | |
| (Reader f) <*> (Reader ra) = Reader $ \r -> f r (ra r) | |
| --} | |
| (Reader f) <*> (Reader ra) = Reader $ f <*> ra | |
| instance Monad (Reader r) where | |
| {-- return :: a -> Reader r a | |
| return :: a -> (r -> a) | |
| --} | |
| return = Reader . const | |
| {-- (>>=) :: Reader r a -> (a -> Reader r b) -> Reader r b | |
| (>>=) :: (r -> a) -> (a -> r -> b) -> (r -> b) | |
| The denition below will force us to define Applicative even if we don't need! | |
| (Reader ra) >>= f = Reader $ (flip runReader) <*> (f . ra) | |
| --} | |
| (Reader ra) >>= f = Reader $ \r -> runReader (f . ra $ r) r | |
| {-- ask :: Reader a a | |
| ask :: Reader (a -> a) | |
| It needs a variable that accepts reader/env and return it to the caller. | |
| This looks a lot like the id function | |
| --} | |
| ask :: Reader a a | |
| ask = Reader id | |
| testFunctor :: IO () | |
| testFunctor = do | |
| putStrLn $ runReader intMessage 0 | |
| putStrLn $ runReader intMessage 1 | |
| putStrLn $ runReader ((++"!!") <$> intMessage) 0 | |
| testApplicative :: IO () | |
| testApplicative = do | |
| putStrLn $ runReader (pure "Zero") 0 | |
| putStrLn $ runReader (addBangMark <*> intMessage) 0 | |
| testMonad :: IO () | |
| testMonad = do | |
| putStrLn $ runReader (return "Zero") 0 | |
| putStrLn $ runReader ( (return . (++"!!")) =<< intMessage) 0 | |
| testAsk :: IO () | |
| testAsk = do | |
| putStrLn $ runReader testAsk' 0 | |
| putStrLn $ runReader testAsk' 1 | |
| {-- using the ask method with reader requires the developer to use pure when return the last value. | |
| When implicity calling the reader with a function like ask we are now computing directly inside | |
| of the Reader context. As oppose of explicity calling the reader by expressing the Reader constructor | |
| and the function, we computing within the reader function (r -> a) which doesn't require one to use | |
| pure because the Reader constructor will return the right context. | |
| --} | |
| testAsk' :: Reader Int String | |
| testAsk' = do | |
| val <- ask | |
| case val of | |
| 0 -> pure "Zero" | |
| _ -> pure "Random Number" | |
| intMessage :: Reader Int String | |
| intMessage = Reader $ \r -> | |
| case r of | |
| 0 -> "Zero" | |
| _ -> "Random Number" | |
| addBangMark :: Reader Int (String -> String) | |
| addBangMark = Reader $ \r -> (++ "!!") | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment