Created
May 3, 2018 22:52
-
-
Save yuanwang-wf/b8b64d921d301f3c58ad05362c5adc0f to your computer and use it in GitHub Desktop.
fp-course
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 InstanceSigs #-} | |
{-# LANGUAGE NoImplicitPrelude #-} | |
{-# LANGUAGE RebindableSyntax #-} | |
{-# LANGUAGE ScopedTypeVariables #-} | |
module Course.Applicative where | |
import Course.Core | |
import Course.ExactlyOne | |
import Course.Functor | |
import Course.List | |
import Course.Optional | |
import qualified Prelude as P (fmap, return, (>>=)) | |
-- | All instances of the `Applicative` type-class must satisfy three laws. | |
-- These laws are not checked by the compiler. These laws are given as: | |
-- | |
-- * The law of associative composition | |
-- `∀a b c. ((.) <$> a <*> b <*> c) ≅ (a <*> (b <*> c))` | |
-- | |
-- * The law of identity | |
-- `∀x. pure id <*> x ≅ x` | |
-- | |
-- * The law of homomorphism | |
-- `∀f x. pure f <*> pure x ≅ pure (f x)` | |
-- | |
-- * The law of composition | |
-- `∀u v w. pure (.) <*> u <*> v <*> w ≅ u <*> (v <*> w)` | |
class Functor f => Applicative f where | |
pure :: | |
a -> f a | |
(<*>) :: | |
f (a -> b) | |
-> f a | |
-> f b | |
infixl 4 <*> | |
-- | Insert into ExactlyOne. | |
-- | |
-- prop> \x -> pure x == ExactlyOne x | |
-- | |
-- >>> ExactlyOne (+10) <*> ExactlyOne 8 | |
-- ExactlyOne 18 | |
instance Applicative ExactlyOne where | |
pure :: | |
a | |
-> ExactlyOne a | |
pure = ExactlyOne | |
(<*>) :: | |
ExactlyOne (a -> b) | |
-> ExactlyOne a | |
-> ExactlyOne b | |
(<*>) (ExactlyOne f) (ExactlyOne a) = ExactlyOne (f a) | |
-- | Insert into a List. | |
-- | |
-- prop> \x -> pure x == x :. Nil | |
-- | |
-- >>> (+1) :. (*2) :. Nil <*> 1 :. 2 :. 3 :. Nil | |
-- [2,3,4,2,4,6] | |
instance Applicative List where | |
pure :: | |
a | |
-> List a | |
pure a = a :. Nil | |
(<*>) :: | |
List (a -> b) | |
-> List a | |
-> List b | |
(<*>) Nil _ = Nil | |
(<*>) (h :. t) ls = map h ls ++ (t <*> ls) | |
-- | Insert into an Optional. | |
-- | |
-- prop> \x -> pure x == Full x | |
-- | |
-- >>> Full (+8) <*> Full 7 | |
-- Full 15 | |
-- | |
-- >>> Empty <*> Full 7 | |
-- Empty | |
-- | |
-- >>> Full (+8) <*> Empty | |
-- Empty | |
instance Applicative Optional where | |
pure :: | |
a | |
-> Optional a | |
pure = Full | |
(<*>) :: | |
Optional (a -> b) | |
-> Optional a | |
-> Optional b | |
(<*>) = applyOptional | |
-- | Insert into a constant function. | |
-- | |
-- >>> ((+) <*> (+10)) 3 | |
-- 16 | |
-- | |
-- >>> ((+) <*> (+5)) 3 | |
-- 11 | |
-- | |
-- >>> ((+) <*> (+5)) 1 | |
-- 7 | |
-- | |
-- >>> ((*) <*> (+10)) 3 | |
-- 39 | |
-- | |
-- >>> ((*) <*> (+2)) 3 | |
-- 15 | |
-- | |
-- prop> \x y -> pure x y == x | |
instance Applicative ((->) t) where | |
pure :: | |
a | |
-> ((->) t a) | |
pure = const | |
(<*>) :: | |
((->) t (a -> b)) | |
-> ((->) t a) | |
-> ((->) t b) | |
(<*>) af fb a = af a $ fb a | |
-- | Apply a binary function in the environment. | |
-- | |
-- >>> lift2 (+) (ExactlyOne 7) (ExactlyOne 8) | |
-- ExactlyOne 15 | |
-- | |
-- >>> lift2 (+) (1 :. 2 :. 3 :. Nil) (4 :. 5 :. Nil) | |
-- [5,6,6,7,7,8] | |
-- | |
-- >>> lift2 (+) (Full 7) (Full 8) | |
-- Full 15 | |
-- | |
-- >>> lift2 (+) (Full 7) Empty | |
-- Empty | |
-- | |
-- >>> lift2 (+) Empty (Full 8) | |
-- Empty | |
-- | |
-- >>> lift2 (+) length sum (listh [4,5,6]) | |
-- 18 | |
lift2 :: | |
Applicative f => | |
(a -> b -> c) | |
-> f a | |
-> f b | |
-> f c | |
lift2 f fa fb = pure f <*> fa <*> fb | |
-- | Apply a ternary function in the environment. | |
-- /can be written using `lift2` and `(<*>)`./ | |
-- | |
-- >>> lift3 (\a b c -> a + b + c) (ExactlyOne 7) (ExactlyOne 8) (ExactlyOne 9) | |
-- ExactlyOne 24 | |
-- | |
-- >>> lift3 (\a b c -> a + b + c) (1 :. 2 :. 3 :. Nil) (4 :. 5 :. Nil) (6 :. 7 :. 8 :. Nil) | |
-- [11,12,13,12,13,14,12,13,14,13,14,15,13,14,15,14,15,16] | |
-- | |
-- >>> lift3 (\a b c -> a + b + c) (Full 7) (Full 8) (Full 9) | |
-- Full 24 | |
-- | |
-- >>> lift3 (\a b c -> a + b + c) (Full 7) (Full 8) Empty | |
-- Empty | |
-- | |
-- >>> lift3 (\a b c -> a + b + c) Empty (Full 8) (Full 9) | |
-- Empty | |
-- | |
-- >>> lift3 (\a b c -> a + b + c) Empty Empty (Full 9) | |
-- Empty | |
-- | |
-- >>> lift3 (\a b c -> a + b + c) length sum product (listh [4,5,6]) | |
-- 138 | |
lift3 :: | |
Applicative f => | |
(a -> b -> c -> d) | |
-> f a | |
-> f b | |
-> f c | |
-> f d | |
lift3 f fa fb fc = lift2 f fa fb <*> fc | |
-- | Apply a quaternary function in the environment. | |
-- /can be written using `lift3` and `(<*>)`./ | |
-- | |
-- >>> lift4 (\a b c d -> a + b + c + d) (ExactlyOne 7) (ExactlyOne 8) (ExactlyOne 9) (ExactlyOne 10) | |
-- ExactlyOne 34 | |
-- | |
-- >>> lift4 (\a b c d -> a + b + c + d) (1 :. 2 :. 3 :. Nil) (4 :. 5 :. Nil) (6 :. 7 :. 8 :. Nil) (9 :. 10 :. Nil) | |
-- [20,21,21,22,22,23,21,22,22,23,23,24,21,22,22,23,23,24,22,23,23,24,24,25,22,23,23,24,24,25,23,24,24,25,25,26] | |
-- | |
-- >>> lift4 (\a b c d -> a + b + c + d) (Full 7) (Full 8) (Full 9) (Full 10) | |
-- Full 34 | |
-- | |
-- >>> lift4 (\a b c d -> a + b + c + d) (Full 7) (Full 8) Empty (Full 10) | |
-- Empty | |
-- | |
-- >>> lift4 (\a b c d -> a + b + c + d) Empty (Full 8) (Full 9) (Full 10) | |
-- Empty | |
-- | |
-- >>> lift4 (\a b c d -> a + b + c + d) Empty Empty (Full 9) (Full 10) | |
-- Empty | |
-- | |
-- >>> lift4 (\a b c d -> a + b + c + d) length sum product (sum . filter even) (listh [4,5,6]) | |
-- 148 | |
lift4 :: | |
Applicative f => | |
(a -> b -> c -> d -> e) | |
-> f a | |
-> f b | |
-> f c | |
-> f d | |
-> f e | |
lift4 f fa fb fc fd = lift3 f fa fb fc <*> fd | |
-- | Apply a nullary function in the environment. | |
lift0 :: | |
Applicative f => | |
a | |
-> f a | |
lift0 = pure | |
-- | Apply a unary function in the environment. | |
-- /can be written using `lift0` and `(<*>)`./ | |
-- | |
-- >>> lift1 (+1) (ExactlyOne 2) | |
-- ExactlyOne 3 | |
-- | |
-- >>> lift1 (+1) Nil | |
-- [] | |
-- | |
-- >>> lift1 (+1) (1 :. 2 :. 3 :. Nil) | |
-- [2,3,4] | |
lift1 :: | |
Applicative f => | |
(a -> b) | |
-> f a | |
-> f b | |
lift1 f fa = lift0 f <*> fa | |
-- | Apply, discarding the value of the first argument. | |
-- Pronounced, right apply. | |
-- | |
-- >>> (1 :. 2 :. 3 :. Nil) *> (4 :. 5 :. 6 :. Nil) | |
-- [4,5,6,4,5,6,4,5,6] | |
-- | |
-- >>> (1 :. 2 :. Nil) *> (4 :. 5 :. 6 :. Nil) | |
-- [4,5,6,4,5,6] | |
-- | |
-- >>> (1 :. 2 :. 3 :. Nil) *> (4 :. 5 :. Nil) | |
-- [4,5,4,5,4,5] | |
-- | |
-- >>> Full 7 *> Full 8 | |
-- Full 8 | |
-- | |
-- prop> \a b c x y z -> (a :. b :. c :. Nil) *> (x :. y :. z :. Nil) == (x :. y :. z :. x :. y :. z :. x :. y :. z :. Nil) | |
-- | |
-- prop> \x y -> Full x *> Full y == Full y | |
(*>) :: | |
Applicative f => | |
f a | |
-> f b | |
-> f b | |
(*>) = lift2 (flip const) | |
-- | Apply, discarding the value of the second argument. | |
-- Pronounced, left apply. | |
-- | |
-- >>> (1 :. 2 :. 3 :. Nil) <* (4 :. 5 :. 6 :. Nil) | |
-- [1,1,1,2,2,2,3,3,3] | |
-- | |
-- >>> (1 :. 2 :. Nil) <* (4 :. 5 :. 6 :. Nil) | |
-- [1,1,1,2,2,2] | |
-- | |
-- >>> (1 :. 2 :. 3 :. Nil) <* (4 :. 5 :. Nil) | |
-- [1,1,2,2,3,3] | |
-- | |
-- >>> Full 7 <* Full 8 | |
-- Full 7 | |
-- | |
-- prop> \x y z a b c -> (x :. y :. z :. Nil) <* (a :. b :. c :. Nil) == (x :. x :. x :. y :. y :. y :. z :. z :. z :. Nil) | |
-- | |
-- prop> \x y -> Full x <* Full y == Full x | |
(<*) :: | |
Applicative f => | |
f b | |
-> f a | |
-> f b | |
(<*) = lift2 const | |
-- | Sequences a list of structures to a structure of list. | |
-- | |
-- >>> sequence (ExactlyOne 7 :. ExactlyOne 8 :. ExactlyOne 9 :. Nil) | |
-- ExactlyOne [7,8,9] | |
-- | |
-- >>> sequence ((1 :. 2 :. 3 :. Nil) :. (1 :. 2 :. Nil) :. Nil) | |
-- [[1,1],[1,2],[2,1],[2,2],[3,1],[3,2]] | |
-- | |
-- >>> sequence (Full 7 :. Empty :. Nil) | |
-- Empty | |
-- | |
-- >>> sequence (Full 7 :. Full 8 :. Nil) | |
-- Full [7,8] | |
-- | |
-- >>> sequence ((*10) :. (+2) :. Nil) 6 | |
-- [60,8] | |
sequence :: | |
Applicative f => | |
List (f a) | |
-> f (List a) | |
sequence = foldRight (lift2 (:.)) (pure Nil) | |
-- | Replicate an effect a given number of times. | |
-- | |
-- >>> replicateA 4 (ExactlyOne "hi") | |
-- ExactlyOne ["hi","hi","hi","hi"] | |
-- | |
-- >>> replicateA 4 (Full "hi") | |
-- Full ["hi","hi","hi","hi"] | |
-- | |
-- >>> replicateA 4 Empty | |
-- Empty | |
-- | |
-- >>> replicateA 4 (*2) 5 | |
-- [10,10,10,10] | |
-- | |
-- >>> replicateA 3 ('a' :. 'b' :. 'c' :. Nil) | |
-- ["aaa","aab","aac","aba","abb","abc","aca","acb","acc","baa","bab","bac","bba","bbb","bbc","bca","bcb","bcc","caa","cab","cac","cba","cbb","cbc","cca","ccb","ccc"] | |
replicateA :: | |
Applicative f => | |
Int | |
-> f a | |
-> f (List a) | |
replicateA n = sequence . replicate n | |
-- | Filter a list with a predicate that produces an effect. | |
-- | |
-- >>> filtering (ExactlyOne . even) (4 :. 5 :. 6 :. Nil) | |
-- ExactlyOne [4,6] | |
-- | |
-- >>> filtering (\a -> if a > 13 then Empty else Full (a <= 7)) (4 :. 5 :. 6 :. Nil) | |
-- Full [4,5,6] | |
-- | |
-- >>> filtering (\a -> if a > 13 then Empty else Full (a <= 7)) (4 :. 5 :. 6 :. 7 :. 8 :. 9 :. Nil) | |
-- Full [4,5,6,7] | |
-- | |
-- >>> filtering (\a -> if a > 13 then Empty else Full (a <= 7)) (4 :. 5 :. 6 :. 13 :. 14 :. Nil) | |
-- Empty | |
-- | |
-- >>> filtering (>) (4 :. 5 :. 6 :. 7 :. 8 :. 9 :. 10 :. 11 :. 12 :. Nil) 8 | |
-- [9,10,11,12] | |
-- | |
-- >>> filtering (const $ True :. True :. Nil) (1 :. 2 :. 3 :. Nil) | |
-- [[1,2,3],[1,2,3],[1,2,3],[1,2,3],[1,2,3],[1,2,3],[1,2,3],[1,2,3]] | |
-- | |
filtering :: | |
Applicative f => | |
(a -> f Bool) | |
-> List a | |
-> f (List a) | |
filtering = | |
error "todo: Course.Applicative#filtering" | |
----------------------- | |
-- SUPPORT LIBRARIES -- | |
----------------------- | |
instance Applicative IO where | |
pure = | |
P.return | |
f <*> a = | |
f P.>>= \f' -> P.fmap f' a | |
return :: | |
Applicative f => | |
a | |
-> f a | |
return = | |
pure | |
fail :: | |
Applicative f => | |
Chars | |
-> f a | |
fail = | |
error . hlist | |
(>>) :: | |
Applicative f => | |
f a | |
-> f b | |
-> f b | |
(>>) = | |
(*>) |
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 FlexibleInstances #-} | |
{-# LANGUAGE NoImplicitPrelude #-} | |
{-# LANGUAGE OverloadedStrings #-} | |
{-# LANGUAGE ScopedTypeVariables #-} | |
-- + Complete the 10 exercises below by filling out the function bodies. | |
-- Replace the function bodies (error "todo: ...") with an appropriate | |
-- solution. | |
-- + These exercises may be done in any order, however: | |
-- Exercises are generally increasing in difficulty, though some people may find later exercise easier. | |
-- + Bonus for using the provided functions or for using one exercise solution to help solve another. | |
-- + Approach with your best available intuition; just dive in and do what you can! | |
module Course.List where | |
import qualified Control.Applicative as A | |
import qualified Control.Monad as M | |
import Course.Core | |
import Course.Optional | |
import qualified Numeric as N | |
import qualified Prelude as P | |
import qualified System.Environment as E | |
-- $setup | |
-- >>> import Test.QuickCheck | |
-- >>> import Course.Core(even, id, const) | |
-- >>> import qualified Prelude as P(fmap, foldr) | |
-- >>> instance Arbitrary a => Arbitrary (List a) where arbitrary = P.fmap ((P.foldr (:.) Nil) :: ([a] -> List a)) arbitrary | |
-- BEGIN Helper functions and data types | |
-- The custom list type | |
data List t = | |
Nil | |
| t :. List t | |
deriving (Eq, Ord) | |
-- Right-associative | |
infixr 5 :. | |
instance Show t => Show (List t) where | |
show = show . foldRight (:) [] | |
-- The list of integers from zero to infinity. | |
infinity :: | |
List Integer | |
infinity = | |
let inf x = x :. inf (x+1) | |
in inf 0 | |
-- functions over List that you may consider using | |
foldRight :: (a -> b -> b) -> b -> List a -> b | |
foldRight _ b Nil = b | |
foldRight f b (h :. t) = f h (foldRight f b t) | |
foldLeft :: (b -> a -> b) -> b -> List a -> b | |
foldLeft _ b Nil = b | |
foldLeft f b (h :. t) = let b' = f b h in b' `seq` foldLeft f b' t | |
-- END Helper functions and data types | |
-- | Returns the head of the list or the given default. | |
-- | |
-- >>> headOr 3 (1 :. 2 :. Nil) | |
-- 1 | |
-- | |
-- >>> headOr 3 Nil | |
-- 3 | |
-- | |
-- prop> \x -> x `headOr` infinity == 0 | |
-- | |
-- prop> \x -> x `headOr` Nil == x | |
headOr :: | |
a | |
-> List a | |
-> a | |
headOr e Nil = e | |
headOr e (head :. list ) = head | |
-- | The product of the elements of a list. | |
-- | |
-- >>> product Nil | |
-- 1 | |
-- | |
-- >>> product (1 :. 2 :. 3 :. Nil) | |
-- 6 | |
-- | |
-- >>> product (1 :. 2 :. 3 :. 4 :. Nil) | |
-- 24 | |
product :: | |
List Int | |
-> Int | |
product = foldRight (*) 1 | |
-- | Sum the elements of the list. | |
-- | |
-- >>> sum (1 :. 2 :. 3 :. Nil) | |
-- 6 | |
-- | |
-- >>> sum (1 :. 2 :. 3 :. 4 :. Nil) | |
-- 10 | |
-- | |
-- prop> \x -> foldLeft (-) (sum x) x == 0 | |
sum :: | |
List Int | |
-> Int | |
sum = foldRight (+) 0 | |
-- | Return the length of the list. | |
-- | |
-- >>> length (1 :. 2 :. 3 :. Nil) | |
-- 3 | |
-- | |
-- prop> \x -> sum (map (const 1) x) == length x | |
length :: | |
List a | |
-> Int | |
length Nil = 0 | |
length (head :. list) = length list + 1 | |
-- | Map the given function on each element of the list. | |
-- | |
-- >>> map (+10) (1 :. 2 :. 3 :. Nil) | |
-- [11,12,13] | |
-- | |
-- prop> \x -> headOr x (map (+1) infinity) == 1 | |
-- | |
-- prop> \x -> map id x == x | |
map :: | |
(a -> b) | |
-> List a | |
-> List b | |
map _ Nil = Nil | |
map f (head :. list) = f head :. map f list | |
-- | Return elements satisfying the given predicate. | |
-- | |
-- >>> filter even (1 :. 2 :. 3 :. 4 :. 5 :. Nil) | |
-- [2,4] | |
-- | |
-- prop> \x -> headOr x (filter (const True) infinity) == 0 | |
-- | |
-- prop> \x -> filter (const True) x == x | |
-- | |
-- prop> \x -> filter (const False) x == Nil | |
filter :: | |
(a -> Bool) | |
-> List a | |
-> List a | |
filter _ Nil = Nil | |
filter f (head :. list) = if f head then head :. filter f list else filter f list | |
-- | Append two lists to a new list. | |
-- | |
-- >>> (1 :. 2 :. 3 :. Nil) ++ (4 :. 5 :. 6 :. Nil) | |
-- [1,2,3,4,5,6] | |
-- | |
-- prop> \x -> headOr x (Nil ++ infinity) == 0 | |
-- | |
-- prop> \x -> headOr x (y ++ infinity) == headOr 0 y | |
-- | |
-- prop> \x -> (x ++ y) ++ z == x ++ (y ++ z) | |
-- | |
-- prop> \x -> x ++ Nil == x | |
(++) :: | |
List a | |
-> List a | |
-> List a | |
(++) ls Nil = ls | |
(++) Nil ls = ls | |
(++) (head :. ls) xs = head :. (ls ++ xs) | |
infixr 5 ++ | |
-- | Flatten a list of lists to a list. | |
-- | |
-- >>> flatten ((1 :. 2 :. 3 :. Nil) :. (4 :. 5 :. 6 :. Nil) :. (7 :. 8 :. 9 :. Nil) :. Nil) | |
-- [1,2,3,4,5,6,7,8,9] | |
-- | |
-- prop> \x -> headOr x (flatten (infinity :. y :. Nil)) == 0 | |
-- | |
-- prop> \x -> headOr x (flatten (y :. infinity :. Nil)) == headOr 0 y | |
-- | |
-- prop> \x -> sum (map length x) == length (flatten x) | |
flatten :: | |
List (List a) | |
-> List a | |
flatten Nil = Nil | |
flatten (head :. list) = head ++ flatten list | |
-- | Map a function then flatten to a list. | |
-- | |
-- >>> flatMap (\x -> x :. x + 1 :. x + 2 :. Nil) (1 :. 2 :. 3 :. Nil) | |
-- [1,2,3,2,3,4,3,4,5] | |
-- | |
-- prop> \x -> headOr x (flatMap id (infinity :. y :. Nil)) == 0 | |
-- | |
-- prop> \x -> headOr x (flatMap id (y :. infinity :. Nil)) == headOr 0 y | |
-- | |
-- prop> \x -> flatMap id (x :: List (List Int)) == flatten x | |
flatMap :: | |
(a -> List b) | |
-> List a | |
-> List b | |
flatMap f = flatten . map f | |
-- | Flatten a list of lists to a list (again). | |
-- HOWEVER, this time use the /flatMap/ function that you just wrote. | |
-- | |
-- prop> \x -> let types = x :: List (List Int) in flatten x == flattenAgain x | |
flattenAgain :: | |
List (List a) | |
-> List a | |
flattenAgain = flatMap id | |
-- | 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 | |
-- this version does not handle infinity list | |
seqOptional :: | |
List (Optional a) | |
-> Optional (List a) | |
-- seqOptional ls = if g ls then (Full . flatMap f) ls else Empty | |
-- where f :: Optional a -> List a | |
-- f Empty = Nil | |
-- f (Full a) = a :. Nil | |
-- g :: List (Optional a) -> Bool | |
-- g Nil = True | |
-- g (Empty :. ls) = False | |
-- g (Full a :. ls) = g ls | |
-- seqOptional = foldLeft f (Full Nil) | |
-- where f :: Optional (List a) -> Optional a -> Optional (List a) | |
-- f = twiceOptional (P.flip (:.)) | |
seqOptional Nil = Full Nil | |
seqOptional (h :. t) = | |
bindOptional (\v -> | |
mapOptional (\w -> v :. w) | |
(seqOptional t)) h | |
--seqOptional Nil = Full Nil | |
--seqOptional (h :. t) = applyOptional (seqOptional t) h | |
-- | Find the first element in the list matching the predicate. | |
-- | |
-- >>> find even (1 :. 3 :. 5 :. Nil) | |
-- Empty | |
-- | |
-- >>> find even Nil | |
-- Empty | |
-- | |
-- >>> find even (1 :. 2 :. 3 :. 5 :. Nil) | |
-- Full 2 | |
-- | |
-- >>> find even (1 :. 2 :. 3 :. 4 :. 5 :. Nil) | |
-- Full 2 | |
-- | |
-- >>> find (const True) infinity | |
-- Full 0 | |
find :: | |
(a -> Bool) | |
-> List a | |
-> Optional a | |
find f = headOr Empty . map Full . filter f | |
-- | Determine if the length of the given list is greater than 4. | |
-- | |
-- >>> lengthGT4 (1 :. 3 :. 5 :. Nil) | |
-- False | |
-- | |
-- >>> lengthGT4 Nil | |
-- False | |
-- | |
-- >>> lengthGT4 (1 :. 2 :. 3 :. 4 :. 5 :. Nil) | |
-- True | |
-- | |
-- >>> lengthGT4 infinity | |
-- True | |
lengthGT4 :: | |
List a | |
-> Bool | |
lengthGT4 = f 0 | |
where f :: Int -> List a -> Bool | |
f count Nil = count > 4 | |
f count (head :. ls) = count > 4 P.|| f (count + 1) ls | |
-- | Reverse a list. | |
-- | |
-- >>> reverse Nil | |
-- [] | |
-- | |
-- >>> take 1 (reverse (reverse largeList)) | |
-- [1] | |
-- | |
-- prop> \x -> let types = x :: List Int in reverse x ++ reverse y == reverse (y ++ x) | |
-- | |
-- prop> \x -> let types = x :: Int in reverse (x :. Nil) == x :. Nil | |
reverse :: | |
List a | |
-> List a | |
--reverse Nil = Nil | |
--reverse (head :. ls) = reverse ls ++ (head :. Nil) | |
-- reverse l = rev l Nil | |
-- where | |
-- rev :: List a -> List a -> List a | |
-- rev Nil a = a | |
-- rev (x :. xs) a = rev xs (x :. a) | |
reverse = foldLeft (P.flip (:.)) Nil | |
-- | Produce an infinite `List` that seeds with the given value at its head, | |
-- then runs the given function for subsequent elements | |
-- | |
-- >>> let (x:.y:.z:.w:._) = produce (+1) 0 in [x,y,z,w] | |
-- [0,1,2,3] | |
-- | |
-- >>> let (x:.y:.z:.w:._) = produce (*2) 1 in [x,y,z,w] | |
-- [1,2,4,8] | |
produce :: | |
(a -> a) | |
-> a | |
-> List a | |
produce f x = x :. produce f (f x) | |
-- | Do anything other than reverse a list. | |
-- Is it even possible? | |
-- | |
-- >>> notReverse Nil | |
-- [] | |
-- | |
-- prop> \x -> let types = x :: List Int in notReverse x ++ notReverse y == notReverse (y ++ x) | |
-- | |
-- prop> \x -> let types = x :: Int in notReverse (x :. Nil) == x :. Nil | |
notReverse :: | |
List a | |
-> List a | |
notReverse Nil = Nil | |
notReverse (head :. ls) = undefined | |
---- End of list exercises | |
largeList :: | |
List Int | |
largeList = | |
listh [1..50000] | |
hlist :: | |
List a | |
-> [a] | |
hlist = | |
foldRight (:) [] | |
listh :: | |
[a] | |
-> List a | |
listh = | |
P.foldr (:.) Nil | |
putStr :: | |
Chars | |
-> IO () | |
putStr = | |
P.putStr . hlist | |
putStrLn :: | |
Chars | |
-> IO () | |
putStrLn = | |
P.putStrLn . hlist | |
readFile :: | |
FilePath | |
-> IO Chars | |
readFile = | |
P.fmap listh . P.readFile . hlist | |
writeFile :: | |
FilePath | |
-> Chars | |
-> IO () | |
writeFile n s = | |
P.writeFile (hlist n) (hlist s) | |
getLine :: | |
IO Chars | |
getLine = | |
P.fmap listh P.getLine | |
getArgs :: | |
IO (List Chars) | |
getArgs = | |
P.fmap (listh . P.fmap listh) E.getArgs | |
isPrefixOf :: | |
Eq a => | |
List a | |
-> List a | |
-> Bool | |
isPrefixOf Nil _ = | |
True | |
isPrefixOf _ Nil = | |
False | |
isPrefixOf (x:.xs) (y:.ys) = | |
x == y && isPrefixOf xs ys | |
isEmpty :: | |
List a | |
-> Bool | |
isEmpty Nil = | |
True | |
isEmpty (_:._) = | |
False | |
span :: | |
(a -> Bool) | |
-> List a | |
-> (List a, List a) | |
span p x = | |
(takeWhile p x, dropWhile p x) | |
break :: | |
(a -> Bool) | |
-> List a | |
-> (List a, List a) | |
break p = | |
span (not . p) | |
dropWhile :: | |
(a -> Bool) | |
-> List a | |
-> List a | |
dropWhile _ Nil = | |
Nil | |
dropWhile p xs@(x:.xs') = | |
if p x | |
then | |
dropWhile p xs' | |
else | |
xs | |
takeWhile :: | |
(a -> Bool) | |
-> List a | |
-> List a | |
takeWhile _ Nil = | |
Nil | |
takeWhile p (x:.xs) = | |
if p x | |
then | |
x :. takeWhile p xs | |
else | |
Nil | |
zip :: | |
List a | |
-> List b | |
-> List (a, b) | |
zip = | |
zipWith (,) | |
zipWith :: | |
(a -> b -> c) | |
-> List a | |
-> List b | |
-> List c | |
zipWith f (a:.as) (b:.bs) = | |
f a b :. zipWith f as bs | |
zipWith _ _ _ = | |
Nil | |
unfoldr :: | |
(a -> Optional (b, a)) | |
-> a | |
-> List b | |
unfoldr f b = | |
case f b of | |
Full (a, z) -> a :. unfoldr f z | |
Empty -> Nil | |
lines :: | |
Chars | |
-> List Chars | |
lines = | |
listh . P.fmap listh . P.lines . hlist | |
unlines :: | |
List Chars | |
-> Chars | |
unlines = | |
listh . P.unlines . hlist . map hlist | |
words :: | |
Chars | |
-> List Chars | |
words = | |
listh . P.fmap listh . P.words . hlist | |
unwords :: | |
List Chars | |
-> Chars | |
unwords = | |
listh . P.unwords . hlist . map hlist | |
listOptional :: | |
(a -> Optional b) | |
-> List a | |
-> List b | |
listOptional _ Nil = | |
Nil | |
listOptional f (h:.t) = | |
let r = listOptional f t | |
in case f h of | |
Empty -> r | |
Full q -> q :. r | |
any :: | |
(a -> Bool) | |
-> List a | |
-> Bool | |
any p = | |
foldRight ((||) . p) False | |
all :: | |
(a -> Bool) | |
-> List a | |
-> Bool | |
all p = | |
foldRight ((&&) . p) True | |
or :: | |
List Bool | |
-> Bool | |
or = | |
any id | |
and :: | |
List Bool | |
-> Bool | |
and = | |
all id | |
elem :: | |
Eq a => | |
a | |
-> List a | |
-> Bool | |
elem x = | |
any (== x) | |
notElem :: | |
Eq a => | |
a | |
-> List a | |
-> Bool | |
notElem x = | |
all (/= x) | |
permutations | |
:: List a -> List (List a) | |
permutations xs0 = | |
let perms Nil _ = | |
Nil | |
perms (t:.ts) is = | |
let interleave' _ Nil r = | |
(ts, r) | |
interleave' f (y:.ys) r = | |
let (us,zs) = interleave' (f . (y:.)) ys r | |
in (y:.us, f (t:.y:.us):.zs) | |
in foldRight (\xs -> snd . interleave' id xs) (perms ts (t:.is)) (permutations is) | |
in xs0 :. perms xs0 Nil | |
intersectBy :: | |
(a -> b -> Bool) | |
-> List a | |
-> List b | |
-> List a | |
intersectBy e xs ys = | |
filter (\x -> any (e x) ys) xs | |
take :: | |
(Num n, Ord n) => | |
n | |
-> List a | |
-> List a | |
take n _ | n <= 0 = | |
Nil | |
take _ Nil = | |
Nil | |
take n (x:.xs) = | |
x :. take (n - 1) xs | |
drop :: | |
(Num n, Ord n) => | |
n | |
-> List a | |
-> List a | |
drop n xs | n <= 0 = | |
xs | |
drop _ Nil = | |
Nil | |
drop n (_:.xs) = | |
drop (n-1) xs | |
repeat :: | |
a | |
-> List a | |
repeat x = | |
x :. repeat x | |
replicate :: | |
(Num n, Ord n) => | |
n | |
-> a | |
-> List a | |
replicate n x = | |
take n (repeat x) | |
reads :: | |
P.Read a => | |
Chars | |
-> Optional (a, Chars) | |
reads s = | |
case P.reads (hlist s) of | |
[] -> Empty | |
((a, q):_) -> Full (a, listh q) | |
read :: | |
P.Read a => | |
Chars | |
-> Optional a | |
read = | |
mapOptional fst . reads | |
readHexs :: | |
(Eq a, Num a) => | |
Chars | |
-> Optional (a, Chars) | |
readHexs s = | |
case N.readHex (hlist s) of | |
[] -> Empty | |
((a, q):_) -> Full (a, listh q) | |
readHex :: | |
(Eq a, Num a) => | |
Chars | |
-> Optional a | |
readHex = | |
mapOptional fst . readHexs | |
readFloats :: | |
(RealFrac a) => | |
Chars | |
-> Optional (a, Chars) | |
readFloats s = | |
case N.readSigned N.readFloat (hlist s) of | |
[] -> Empty | |
((a, q):_) -> Full (a, listh q) | |
readFloat :: | |
(RealFrac a) => | |
Chars | |
-> Optional a | |
readFloat = | |
mapOptional fst . readFloats | |
instance IsString (List Char) where | |
fromString = | |
listh | |
type Chars = | |
List Char | |
type FilePath = | |
List Char | |
strconcat :: | |
[Chars] | |
-> P.String | |
strconcat = | |
P.concatMap hlist | |
stringconcat :: | |
[P.String] | |
-> P.String | |
stringconcat = | |
P.concat | |
show' :: | |
Show a => | |
a | |
-> List Char | |
show' = | |
listh . show | |
instance P.Functor List where | |
fmap f = | |
listh . P.fmap f . hlist | |
instance A.Applicative List where | |
(<*>) = | |
M.ap | |
pure = | |
(:. Nil) | |
instance P.Monad List where | |
(>>=) = | |
flip flatMap | |
return = | |
(:. Nil) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment