Skip to content

Instantly share code, notes, and snippets.

@yuanwang-wf
Created May 3, 2018 22:52
Show Gist options
  • Save yuanwang-wf/b8b64d921d301f3c58ad05362c5adc0f to your computer and use it in GitHub Desktop.
Save yuanwang-wf/b8b64d921d301f3c58ad05362c5adc0f to your computer and use it in GitHub Desktop.
fp-course
{-# 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
(>>) =
(*>)
{-# 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