parent
285f44274c
commit
c6779197b1
12 changed files with 473 additions and 0 deletions
@ -0,0 +1,2 @@ |
||||
# Exercises: Lookups |
||||
see src/lookups.hs |
@ -0,0 +1,8 @@ |
||||
# List Applicative Exercise |
||||
see src/List.hs |
||||
|
||||
# ZipList Applicative Exercise |
||||
see src/List.hs |
||||
|
||||
# Exercuse: Variation on Either |
||||
see src/Validation.hs |
@ -0,0 +1,12 @@ |
||||
# Chapter Excercises |
||||
## fill in the types |
||||
1. `pure :: a -> [a]`, `(<*>) :: [(a -> b)] -> [a] -> [b]` |
||||
2. `pure :: a -> IO a`, `(<*>) :: IO (a -> b) -> IO a -> IO b` |
||||
3. `pure :: a -> (b,a)`, `(<*>) :: (c, (a -> b)) -> (c, a) -> (c, b)` |
||||
4. `pure :: a -> (e -> a)`, `(<*>) :: (e -> (a -> b))) -> (e -> a) -> (e -> b)` |
||||
|
||||
## Write instances |
||||
see src/instances.hs |
||||
|
||||
## Combinations |
||||
see src/combinations.hs |
@ -0,0 +1,22 @@ |
||||
module BadMonoid where |
||||
|
||||
import Data.Monoid |
||||
import Test.QuickCheck |
||||
import Test.QuickCheck.Checkers |
||||
import Test.QuickCheck.Classes |
||||
|
||||
data Bull = Fools | Twoo deriving (Eq, Show) |
||||
|
||||
instance Arbitrary Bull where |
||||
arbitrary = |
||||
frequency [ (1, return Fools), (1, return Twoo)] |
||||
|
||||
instance Monoid Bull where |
||||
mempty = Fools |
||||
mappend _ _ = Fools |
||||
|
||||
instance EqProp Bull where |
||||
(=-=) = eq |
||||
|
||||
main :: IO () |
||||
main = quickBatch (monoid Twoo) |
@ -0,0 +1,11 @@ |
||||
module Constant where |
||||
|
||||
newtype Constant a b = Constant { getConstant :: a } |
||||
deriving (Eq, Ord, Show) |
||||
|
||||
instance Functor (Constant a) where |
||||
fmap _ (Constant a) = (Constant a) |
||||
|
||||
instance Monoid a => Applicative (Constant a) where |
||||
pure _ = Constant mempty |
||||
(<*>) (Constant a) (Constant a') = Constant (mappend a a') |
@ -0,0 +1,11 @@ |
||||
module Identity where |
||||
|
||||
newtype Identity a = Identity a deriving (Show, Eq, Ord) |
||||
|
||||
instance Functor Identity where |
||||
fmap f (Identity a) = Identity (f a) |
||||
|
||||
instance Applicative Identity where |
||||
pure = Identity |
||||
(<*>) (Identity f) = fmap f |
||||
|
@ -0,0 +1,159 @@ |
||||
module List where |
||||
|
||||
import Data.Functor ((<$>)) |
||||
import Data.Monoid ((<>)) |
||||
|
||||
import Test.QuickCheck.Gen (sized) |
||||
import Control.Applicative (liftA2) |
||||
|
||||
import Test.QuickCheck |
||||
import Test.QuickCheck.Checkers |
||||
import Test.QuickCheck.Classes |
||||
|
||||
data List a = Nil | Cons a (List a) deriving (Eq, Show) |
||||
|
||||
-- My original implementation (before looking at the list) |
||||
-- instance Applicative List where |
||||
-- pure a = Cons a Nil |
||||
-- _ <*> Nil = Nil -- strictly not neccessary but slightly faster? |
||||
-- -- if the List is empty then the last pattern mach |
||||
-- -- will be |
||||
-- -- (<>) ((<$>) f Nil) (fl <*> Nil) |
||||
-- -- (<>) Nil ((<>) ((<$>) f Nil) (fl' <> Nil)) |
||||
-- -- Which will continue until fl/fl' is Nil and which |
||||
-- -- will pattern match with second pattern match |
||||
|
||||
-- Nil <*> _ = Nil |
||||
-- (Cons f fl) <*> l = |
||||
-- (<>) ((<$>) f l) (fl <*> l) |
||||
|
||||
|
||||
instance Functor List where |
||||
fmap _ Nil = Nil |
||||
fmap f (Cons a l) = Cons (f a) (f <$> l) |
||||
|
||||
instance Monoid (List a) where |
||||
mempty = Nil |
||||
mappend Nil l = l |
||||
mappend l Nil = l |
||||
mappend (Cons a al) l = Cons a $ al <> l |
||||
|
||||
-- The append function from the book is just (<>) |
||||
-- from the Monoid typeclass |
||||
-- append :: List a -> List a -> List a |
||||
-- append Nil ys = ys |
||||
-- append (Cons x xs) ys = Cons x $ xs `append` ys |
||||
|
||||
-- We probably could also implemnt the Foldable typeclass, so |
||||
-- we can start using foldr, but this _is_ foldr :) |
||||
fold :: (a -> b -> b) -> b -> List a -> b |
||||
fold _ b Nil = b |
||||
fold f b (Cons h t) = f h (fold f b t) |
||||
|
||||
concat' :: List (List a) -> List a |
||||
concat' = fold (<>) Nil |
||||
|
||||
flatMap :: (a -> List b) -> List a -> List b |
||||
flatMap f = (concat' . (<$>) f) |
||||
|
||||
|
||||
-- Imagine we have a List of functions `fs` and a List of elements `as` |
||||
-- For each f in fs we want to fmap it over al and append the result. |
||||
-- We can use the now defined flatMap for this, but we should figure |
||||
-- out what is what. (a -> List b) -> List a -> List b |
||||
|
||||
-- Option 1 |
||||
-- If `List a` is the `as` then (a -> List b) should be a function |
||||
-- that takes an `a` and has all functions applied to it |
||||
-- This would be akin to: fmap ($a) fs |
||||
|
||||
-- instance Applicative List where |
||||
-- pure = flip Cons Nil |
||||
-- fs <*> xs = flatMap (\x -> ($x) <$> fs) xs |
||||
|
||||
-- But this doesn't look so nice. We could look at it slightly different |
||||
-- Option 2 |
||||
-- If `List a` is the `fs` then (a -> List b) should be a function that |
||||
-- takes an `f` and applies it to all `as`. |
||||
-- This would be fmap f as or \f -> fmap f xs or (`fmap` xs) |
||||
instance Applicative List where |
||||
pure = flip Cons Nil |
||||
fs <*> xs = flatMap (<$> xs) fs |
||||
|
||||
-- First attempt at Arbitrary for List |
||||
-- Slow for the composition test |
||||
fromList :: List a -> [a] |
||||
fromList Nil = [] |
||||
fromList (Cons a l) = a : fromList l |
||||
|
||||
toList :: [a] -> List a |
||||
toList [] = Nil |
||||
toList (x:xs) = Cons x (toList xs) |
||||
|
||||
instance Arbitrary a => Arbitrary (List a) where |
||||
arbitrary = do |
||||
as <- listOf arbitrary |
||||
return $ toList as |
||||
|
||||
-- Have to find a good balance for Nil |
||||
-- instance Arbitrary a => Arbitrary (List a) where |
||||
-- arbitrary = do |
||||
-- a <- arbitrary |
||||
-- l <- arbitrary |
||||
-- frequency [(9,return $ Cons a l), (1, return Nil)] |
||||
|
||||
-- Peaking at arbitrary for [], also long which made my first |
||||
-- version actually pretty ok! The difference is probably in the |
||||
-- size of lists generated between this and the other frequency one |
||||
|
||||
-- replicateM' :: (Applicative m) => Int -> m a -> m (List a) |
||||
-- replicateM' cnt0 f = |
||||
-- loop cnt0 |
||||
-- where loop cnt |
||||
-- | cnt <= 0 = pure Nil |
||||
-- | otherwise = liftA2 Cons f (loop (cnt - 1)) |
||||
|
||||
-- vectorOf' :: Int -> Gen a -> Gen (List a) |
||||
-- vectorOf' = replicateM' |
||||
|
||||
-- listOf' :: Gen a -> Gen (List a) |
||||
-- listOf' gen = sized $ \n -> |
||||
-- do k <- choose (0,n) |
||||
-- vectorOf' k gen |
||||
|
||||
|
||||
-- instance Arbitrary a => Arbitrary (List a) where |
||||
-- arbitrary = listOf' arbitrary |
||||
|
||||
instance Eq a => EqProp (List a) where |
||||
(=-=) = eq |
||||
|
||||
-- take' :: Int -> List a -> List a |
||||
-- take' = undefined |
||||
|
||||
-- newtype ZipList' a = ZipList' (List a) deriving (Eq, Show) |
||||
|
||||
-- instance Eq a => EqProp (ZipList' a) where |
||||
-- xs =-= ys = xs' `eq` ys' |
||||
-- where xs' = let (ZipList' l) = xs |
||||
-- in take' 3000 l |
||||
-- ys' = let (ZipList' l) = ys |
||||
-- in take' 3000 l |
||||
|
||||
-- instance Functor ZipList' where |
||||
-- (<$>) f (ZipList' xs) = ZipList' $ (<$>) f xs |
||||
|
||||
-- instance Applicative ZipList' where |
||||
-- pure a = ZipList' (Cons a Nil) |
||||
-- (ZipList' Nil) <*> _ = ZipList' Nil |
||||
-- _ <*> (ZipList' Nil) = ZipList' Nil |
||||
-- (ZipList' (Cons f fl)) <*> (ZipList' (Cons a as)) = |
||||
-- ZipList' $ Cons (f a) (recurse fl as) |
||||
-- where recurse fl' as' = |
||||
-- let (ZipList' z) = ((ZipList' fl') <*> (ZipList' as')) |
||||
-- in z |
||||
|
||||
main :: IO () |
||||
main = do |
||||
quickBatch (monoid (Nil :: List Int)) |
||||
quickBatch (applicative (Nil :: List (Int,Int,Int))) |
@ -0,0 +1,28 @@ |
||||
module Person where |
||||
|
||||
validateLength :: Int -> String -> Maybe String |
||||
validateLength maxLen s = |
||||
if (length s) > maxLen |
||||
then Nothing |
||||
else Just s |
||||
|
||||
newtype Name = Name String deriving (Eq, Show) |
||||
newtype Address = Address String deriving (Eq, Show) |
||||
|
||||
mkName :: String -> Maybe Name |
||||
mkName s = fmap Name $ validateLength 25 s |
||||
|
||||
mkAddress :: String -> Maybe Address |
||||
mkAddress a = fmap Address $ validateLength 100 a |
||||
|
||||
data Person = Person Name Address deriving (Eq, Show) |
||||
|
||||
mkPerson :: String -> String -> Maybe Person |
||||
-- mkPerson n a = |
||||
-- case mkName n of |
||||
-- Nothing -> Nothing |
||||
-- Just n' -> |
||||
-- case mkAddress a of |
||||
-- Nothing -> Nothing |
||||
-- Just a' -> Just $ Person n' a' |
||||
mkPerson n a = Person <$> mkName n <*> mkAddress a |
@ -0,0 +1,36 @@ |
||||
module Validation' where |
||||
|
||||
import Test.QuickCheck |
||||
import Test.QuickCheck.Checkers |
||||
import Test.QuickCheck.Classes |
||||
|
||||
data Validation' e a = Failure' e | Success' a deriving (Eq, Show) |
||||
|
||||
instance Functor (Validation' e) where |
||||
fmap _ (Failure' e) = Failure' e |
||||
fmap f (Success' s) = Success' $ f s |
||||
|
||||
instance Monoid e => Applicative (Validation' e) where |
||||
pure = Success' |
||||
(Failure' e) <*> (Failure' e') = Failure' $ e `mappend` e' |
||||
(Failure' e) <*> _ = Failure' e |
||||
_ <*> (Failure' e) = Failure' e |
||||
(Success' f) <*> s = fmap f s |
||||
|
||||
instance (Arbitrary a, Arbitrary b) => Arbitrary (Validation' a b) where |
||||
arbitrary = do |
||||
a <- arbitrary |
||||
b <- arbitrary |
||||
elements [Failure' a, Success' b] |
||||
|
||||
instance (Eq a, Eq b) => EqProp (Validation' a b) where |
||||
(=-=) (Failure' _) (Success' _) = property False |
||||
(=-=) (Success' _) (Failure' _) = property False |
||||
(=-=) a b = eq a b |
||||
|
||||
test :: Validation' String (Int, Int, Int) |
||||
test = undefined |
||||
|
||||
main :: IO () |
||||
main = do |
||||
quickBatch (applicative test) |
@ -0,0 +1,12 @@ |
||||
module Combinations where |
||||
|
||||
import Control.Applicative (liftA3) |
||||
|
||||
stops :: String |
||||
stops = "pbtdkg" |
||||
|
||||
vowels :: String |
||||
vowels = "aeiou" |
||||
|
||||
combos :: [a] -> [b] -> [c] -> [(a,b,c)] |
||||
combos = liftA3 (,,) |
@ -0,0 +1,129 @@ |
||||
module Instances where |
||||
|
||||
import Data.Monoid (Sum, Product) |
||||
|
||||
import Test.QuickCheck |
||||
import Test.QuickCheck.Checkers |
||||
import Test.QuickCheck.Classes |
||||
|
||||
-- 1 |
||||
data Pair a = Pair a a deriving (Show, Eq) |
||||
instance Functor Pair where |
||||
fmap f (Pair a a') = Pair (f a) (f a') |
||||
instance Applicative Pair where |
||||
pure x = Pair x x |
||||
(<*>) (Pair f f') (Pair a a') = Pair (f a) (f' a') |
||||
instance Arbitrary a => Arbitrary (Pair a) where |
||||
arbitrary = do |
||||
a <- arbitrary |
||||
a' <- arbitrary |
||||
return $ Pair a a' |
||||
instance Eq a => EqProp (Pair a) where |
||||
(=-=) = eq |
||||
type PairType = Pair (Int, Int, Int) |
||||
|
||||
-- 2 |
||||
data Two a b = Two a b deriving (Show, Eq) |
||||
instance Functor (Two a) where |
||||
fmap f (Two a b) = Two a (f b) |
||||
instance Monoid a => Applicative (Two a) where |
||||
pure = Two mempty |
||||
(<*>) (Two a f) (Two a' b) = Two (mappend a a') (f b) |
||||
instance (Arbitrary a, Arbitrary b) => Arbitrary (Two a b) where |
||||
arbitrary = do |
||||
a <- arbitrary |
||||
b <- arbitrary |
||||
return $ Two a b |
||||
instance (Eq a, Eq b) => EqProp (Two a b) where |
||||
(=-=) = eq |
||||
type TwoType = Two String (Int,Int,Int) |
||||
|
||||
-- 3 |
||||
data Three a b c = Three a b c deriving (Show, Eq) |
||||
instance Functor (Three a b) where |
||||
fmap f (Three a b c) = Three a b (f c) |
||||
instance (Monoid a, Monoid b) => Applicative (Three a b) where |
||||
pure x = Three mempty mempty x |
||||
(<*>) (Three a b f) (Three a' b' c) = Three (mappend a a') |
||||
(mappend b b') |
||||
(f c) |
||||
instance (Arbitrary a, Arbitrary b, Arbitrary c) |
||||
=> Arbitrary (Three a b c) where |
||||
arbitrary = do |
||||
a <- arbitrary |
||||
b <- arbitrary |
||||
c <- arbitrary |
||||
return $ Three a b c |
||||
instance (Eq a, Eq b, Eq c) => EqProp (Three a b c) where |
||||
(=-=) = eq |
||||
type ThreeType = Three String (Sum Int) (Int, Int, Int) |
||||
|
||||
-- 4 |
||||
data Three' a b = Three' a b b deriving (Show, Eq) |
||||
instance Functor (Three' a) where |
||||
fmap f (Three' a b b') = Three' a (f b) (f b') |
||||
instance Monoid a => Applicative (Three' a) where |
||||
pure x = Three' mempty x x |
||||
(<*>) (Three' a f f') (Three' a' b b') = Three' (mappend a a') |
||||
(f b) (f' b') |
||||
instance (Arbitrary a, Arbitrary b) => Arbitrary (Three' a b) where |
||||
arbitrary = do |
||||
a <- arbitrary |
||||
b <- arbitrary |
||||
b' <- arbitrary |
||||
return $ Three' a b b' |
||||
instance (Eq a, Eq b) => EqProp (Three' a b) where |
||||
(=-=) = eq |
||||
type Three'Type = Three' String (Int,Int,Int) |
||||
|
||||
-- 5 |
||||
data Four a b c d = Four a b c d deriving (Show, Eq) |
||||
instance Functor (Four a b c) where |
||||
fmap f (Four a b c d) = Four a b c (f d) |
||||
instance (Monoid a, Monoid b, Monoid c) => Applicative (Four a b c) where |
||||
pure = Four mempty mempty mempty |
||||
(<*>) (Four a b c f) (Four a' b' c' d) = Four (mappend a a') |
||||
(mappend b b') |
||||
(mappend c c') |
||||
(f d) |
||||
instance (Arbitrary a, Arbitrary b, Arbitrary c, Arbitrary d) |
||||
=> Arbitrary (Four a b c d) where |
||||
arbitrary = do |
||||
a <- arbitrary |
||||
b <- arbitrary |
||||
c <- arbitrary |
||||
d <- arbitrary |
||||
return $ Four a b c d |
||||
instance (Eq a, Eq b, Eq c, Eq d) => EqProp (Four a b c d) where |
||||
(=-=) = eq |
||||
type FourType = Four String (Sum Int) Ordering (Int, Int, Int) |
||||
|
||||
-- 6 |
||||
data Four' a b = Four' a a a b deriving (Show, Eq) |
||||
instance Functor (Four' a) where |
||||
fmap f (Four' a a' a'' b) = Four' a a' a'' (f b) |
||||
instance (Monoid a) => Applicative (Four' a) where |
||||
pure = Four' mempty mempty mempty |
||||
(<*>) (Four' a b c f) (Four' a' b' c' d) = Four' (mappend a a') |
||||
(mappend b b') |
||||
(mappend c c') |
||||
(f d) |
||||
instance (Arbitrary a, Arbitrary b) => Arbitrary (Four' a b) where |
||||
arbitrary = do |
||||
a <- arbitrary |
||||
a' <- arbitrary |
||||
a'' <- arbitrary |
||||
b <- arbitrary |
||||
return $ Four' a a' a'' b |
||||
instance (Eq a, Eq b) => EqProp (Four' a b) where |
||||
(=-=) = eq |
||||
type Four'Type = Four' String (Int,Int,Int) |
||||
|
||||
main :: IO () |
||||
main = do |
||||
quickBatch (applicative (undefined :: PairType)) |
||||
quickBatch (applicative (undefined :: TwoType)) |
||||
quickBatch (applicative (undefined :: ThreeType )) |
||||
quickBatch (applicative (undefined :: Three'Type)) |
||||
quickBatch (applicative (undefined :: FourType)) |
||||
quickBatch (applicative (undefined :: Four'Type)) |
@ -0,0 +1,43 @@ |
||||
module Lookups where |
||||
|
||||
import Data.List (elemIndex) |
||||
|
||||
xs :: [Integer] |
||||
xs = [1,2,3] |
||||
ys :: [Integer] |
||||
ys = [4,5,6] |
||||
|
||||
added :: Maybe Integer |
||||
added = (+3) <$> (lookup 3 $ zip xs ys) |
||||
|
||||
y :: Maybe Integer |
||||
y = lookup 3 $ zip xs ys |
||||
|
||||
z :: Maybe Integer |
||||
z = lookup 2 $ zip xs ys |
||||
|
||||
tupled :: Maybe (Integer, Integer) |
||||
tupled = (,) <$> y <*> z |
||||
|
||||
-- 3 |
||||
x' :: Maybe Int |
||||
x' = elemIndex 3 ([1,2,3,4,5] :: [Integer]) |
||||
|
||||
y' :: Maybe Int |
||||
y' = elemIndex 4 ([1,2,3,4,5] :: [Integer]) |
||||
|
||||
max' :: Int -> Int -> Int |
||||
max' = max |
||||
|
||||
maxed :: Maybe Int |
||||
maxed = max' <$> x' <*> y' |
||||
|
||||
-- 4 |
||||
x'' :: Maybe Integer |
||||
x'' = lookup 3 $ zip xs ys |
||||
|
||||
y'' :: Maybe Integer |
||||
y'' = lookup 2 $ zip xs ys |
||||
|
||||
summed :: Maybe Integer |
||||
summed = pure sum <*> ((,) <$> x'' <*> y'') |
Loading…
Reference in new issue