Complete exercises for Reader and State chapters
It's beautiful how State is just Reader that returns a tuple of (a, r) instead
of just a, allowing you to modify the environment (i.e. state).
```haskell
newtype Reader r a = Reader { runReader :: r -> a }
newtype State s a = State { runState :: s -> (a, s) }
```
			
			
This commit is contained in:
		
							parent
							
								
									c4fe3c92c7
								
							
						
					
					
						commit
						ee1aeee5f8
					
				
					 2 changed files with 242 additions and 0 deletions
				
			
		
							
								
								
									
										149
									
								
								scratch/haskell-programming-from-first-principles/reader.hs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										149
									
								
								scratch/haskell-programming-from-first-principles/reader.hs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,149 @@ | |||
| module Reader where | ||||
| 
 | ||||
| import Data.Char | ||||
| import Data.Function ((&)) | ||||
| import Data.Functor ((<&>)) | ||||
| import qualified Control.Applicative as A | ||||
| import qualified Data.Maybe as MB | ||||
| 
 | ||||
| cap :: String -> String | ||||
| cap xs = xs <&> toUpper | ||||
| 
 | ||||
| rev :: String -> String | ||||
| rev = reverse | ||||
| 
 | ||||
| compose :: String -> String | ||||
| compose xs = xs & rev . cap | ||||
| 
 | ||||
| fmapped :: String -> String | ||||
| fmapped xs = xs & rev <$> cap | ||||
| 
 | ||||
| tupled :: String -> (String, String) | ||||
| tupled xs = A.liftA2 (,) cap rev $ xs | ||||
| 
 | ||||
| tupled' :: String -> (String, String) | ||||
| tupled' = do | ||||
|   capResult <- cap | ||||
|   revResult <- rev | ||||
|   pure (revResult, capResult) | ||||
| 
 | ||||
| -------------------------------------------------------------------------------- | ||||
| 
 | ||||
| newtype Reader r a = Reader { runReader :: r -> a } | ||||
| 
 | ||||
| ask :: Reader a a | ||||
| ask = Reader id | ||||
| 
 | ||||
| -------------------------------------------------------------------------------- | ||||
| 
 | ||||
| newtype HumanName = HumanName String | ||||
|   deriving (Eq, Show) | ||||
| 
 | ||||
| newtype DogName = DogName String | ||||
|   deriving (Eq, Show) | ||||
| 
 | ||||
| newtype Address = Address String | ||||
|   deriving (Eq, Show) | ||||
| 
 | ||||
| data Person | ||||
|   = Person | ||||
|   { humanName :: HumanName | ||||
|   , dogName :: DogName | ||||
|   , address :: Address | ||||
|   } deriving (Eq, Show) | ||||
| 
 | ||||
| data Dog | ||||
|   = Dog | ||||
|   { dogsName :: DogName | ||||
|   , dogsAddress :: Address | ||||
|   } deriving (Eq, Show) | ||||
| 
 | ||||
| pers :: Person | ||||
| pers = | ||||
|   Person (HumanName "Big Bird") | ||||
|          (DogName "Barkley") | ||||
|          (Address "Sesame Street") | ||||
| 
 | ||||
| chris :: Person | ||||
| chris = | ||||
|   Person (HumanName "Chris Allen") | ||||
|          (DogName "Papu") | ||||
|          (Address "Austin") | ||||
| 
 | ||||
| getDog :: Person -> Dog | ||||
| getDog p = | ||||
|   Dog (dogName p) (address p) | ||||
| 
 | ||||
| getDogR :: Person -> Dog | ||||
| getDogR = | ||||
|   A.liftA2 Dog dogName address | ||||
| 
 | ||||
| -------------------------------------------------------------------------------- | ||||
| 
 | ||||
| myLiftA2 :: Applicative f => (a -> b -> c) -> f a -> f b -> f c | ||||
| myLiftA2 f x y = | ||||
|   f <$> x <*> y | ||||
| 
 | ||||
| asks :: (r -> a) -> Reader r a | ||||
| asks f = Reader f | ||||
| 
 | ||||
| -------------------------------------------------------------------------------- | ||||
| 
 | ||||
| instance Functor (Reader a) where | ||||
|   fmap f (Reader ab) = Reader $ f . ab | ||||
| 
 | ||||
| instance Applicative (Reader a) where | ||||
|   pure x = Reader $ \_ -> x | ||||
|   (Reader rab) <*> (Reader ra) = Reader $ do | ||||
|     ab <- rab | ||||
|     fmap ab ra | ||||
| 
 | ||||
| -------------------------------------------------------------------------------- | ||||
| 
 | ||||
| instance Monad (Reader r) where | ||||
|   return = pure | ||||
|   -- (>>=) :: Reader r a -> (a -> Reader r b) -> Reader r b | ||||
|   (Reader x) >>= f = undefined | ||||
| 
 | ||||
| -------------------------------------------------------------------------------- | ||||
| 
 | ||||
| x = [1..3] | ||||
| y = [4..6] | ||||
| z = [7..9] | ||||
| 
 | ||||
| xs :: Maybe Integer | ||||
| xs = zip x y & lookup 3 | ||||
| 
 | ||||
| ys :: Maybe Integer | ||||
| ys = zip y z & lookup 6 | ||||
| 
 | ||||
| zs :: Maybe Integer | ||||
| zs = zip x y & lookup 4 | ||||
| 
 | ||||
| z' :: Integer -> Maybe Integer | ||||
| z' n = zip x y & lookup n | ||||
| 
 | ||||
| x1 :: Maybe (Integer, Integer) | ||||
| x1 = A.liftA2 (,) xs ys | ||||
| 
 | ||||
| x2 :: Maybe (Integer, Integer) | ||||
| x2 = A.liftA2 (,) ys zs | ||||
| 
 | ||||
| x3 :: Integer -> (Maybe Integer, Maybe Integer) | ||||
| x3 n = (z' n, z' n) | ||||
| 
 | ||||
| summed :: Num a => (a, a) -> a | ||||
| summed (x, y) = x + y | ||||
| 
 | ||||
| bolt :: Integer -> Bool | ||||
| bolt x = x > 3 && x < 8 | ||||
| 
 | ||||
| main :: IO () | ||||
| main = do | ||||
|   print $ sequenceA [Just 3, Just 2, Just 1] | ||||
|   print $ sequenceA [x, y] | ||||
|   print $ sequenceA [xs, ys] | ||||
|   print $ summed <$> ((,) <$> xs <*> ys) | ||||
|   print $ bolt 7 | ||||
|   print $ bolt <$> z | ||||
|   print $ sequenceA [(>3), (<8) ,even] 7 | ||||
							
								
								
									
										93
									
								
								scratch/haskell-programming-from-first-principles/state.hs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								scratch/haskell-programming-from-first-principles/state.hs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,93 @@ | |||
| module StateScratch where | ||||
| 
 | ||||
| -------------------------------------------------------------------------------- | ||||
| import System.Random | ||||
| -- import Control.Monad.Trans.State | ||||
| import Data.Function ((&)) | ||||
| 
 | ||||
| import qualified Control.Applicative as Ap | ||||
| import qualified Control.Monad as M | ||||
| -------------------------------------------------------------------------------- | ||||
| 
 | ||||
| data Die | ||||
|   = DieOne | ||||
|   | DieTwo | ||||
|   | DieThree | ||||
|   | DieFour | ||||
|   | DieFive | ||||
|   | DieSix | ||||
|   deriving (Eq, Show) | ||||
| 
 | ||||
| intToDie :: Integer -> Maybe Die | ||||
| intToDie 1 = Just DieOne | ||||
| intToDie 2 = Just DieTwo | ||||
| intToDie 3 = Just DieThree | ||||
| intToDie 4 = Just DieFour | ||||
| intToDie 5 = Just DieFive | ||||
| intToDie 6 = Just DieSix | ||||
| intToDie _ = Nothing | ||||
| 
 | ||||
| rollDie :: Moi StdGen Die | ||||
| rollDie = do | ||||
|   (n, s) <- randomR (1, 6) | ||||
|   case intToDie n of | ||||
|     Just d  -> pure (d, s) | ||||
|     Nothing -> pure (DieOne, s) | ||||
| 
 | ||||
| rollsToGetN :: Integer -> StdGen -> [Die] | ||||
| rollsToGetN n g = go 0 [] g | ||||
|   where | ||||
|     go sum result gen | ||||
|       | sum >= n = result | ||||
|       | otherwise = | ||||
|         let (dice, nextGen) = randomR (1, 6) gen | ||||
|         in case intToDie dice of | ||||
|           Nothing -> go (sum + dice) result nextGen | ||||
|           Just d  -> go (sum + dice) (d : result) nextGen | ||||
| 
 | ||||
| -------------------------------------------------------------------------------- | ||||
| 
 | ||||
| newtype Moi s a = Moi { runMoi :: s -> (a, s) } | ||||
| 
 | ||||
| instance Functor (Moi s) where | ||||
|   fmap f (Moi run) = | ||||
|     Moi $ \s -> let (x, t) = run s | ||||
|                 in (f x, t) | ||||
| 
 | ||||
| instance Applicative (Moi s) where | ||||
|   pure x = Moi $ \s -> (x, s) | ||||
|   (Moi f) <*> (Moi run) = | ||||
|     Moi $ \s -> let (g, t) = f s | ||||
|                     (x, u) = run t | ||||
|                 in (g x, u) | ||||
| 
 | ||||
| instance Monad (Moi s) where | ||||
|   (Moi run1) >>= f = | ||||
|     Moi $ \s -> let (x, t) = run1 s | ||||
|                     (Moi run2) = f x | ||||
|                 in run2 t | ||||
| 
 | ||||
| -------------------------------------------------------------------------------- | ||||
| 
 | ||||
| fizzBuzz :: Integer -> String | ||||
| fizzBuzz n | n `mod` 15 == 0 = "FizzBuzz" | ||||
|            | n `mod`  5 == 0 = "Buzz" | ||||
|            | n `mod`  3 == 0 = "Fizz" | ||||
|            | otherwise       = show n | ||||
| 
 | ||||
| -------------------------------------------------------------------------------- | ||||
| 
 | ||||
| get :: Moi s s | ||||
| get = Moi $ \s -> (s, s) | ||||
| 
 | ||||
| put :: s -> Moi s () | ||||
| put x = Moi $ \s -> ((), x) | ||||
| 
 | ||||
| exec :: Moi s a -> s -> s | ||||
| exec (Moi run) x = x & run & snd | ||||
| 
 | ||||
| eval :: Moi s a -> s -> a | ||||
| eval (Moi run) x = x & run & fst | ||||
| 
 | ||||
| modify :: (s -> s) -> Moi s () | ||||
| modify f = Moi $ \s -> ((), f s) | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue