Last active
January 23, 2019 18:11
-
-
Save solomon-b/55824dab69b62c426b58fd1a1ce81afd to your computer and use it in GitHub Desktop.
Notes from Bananas, Lenses, Envelopes, and Barbed Wire. Will clean these notes up at some point. The Haskell Implementation is a old. Refer to this version: https://gist.github.com/ssbothwell/5464663d1c111de0e49342ae6ea12309
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
| {-# Language | |
| FlexibleContexts, | |
| UndecidableInstances, | |
| TypeSynonymInstances, | |
| DeriveGeneric, | |
| DeriveDataTypeable, | |
| DeriveFunctor, | |
| StandaloneDeriving, | |
| ScopedTypeVariables, | |
| TypeFamilies #-} | |
| module RecursionSchemesNotes where | |
| import Data.List | |
| import Data.Data | |
| import GHC.Generics | |
| import Test.QuickCheck | |
| -------------------- | |
| -- List Morphisms -- | |
| -------------------- | |
| cataL :: (a -> b -> b) -> b -> [a] -> b | |
| cataL _ b [] = b | |
| cataL f b (a:as) = a `f` (cataL f b as) | |
| lengthL :: [a] -> Int | |
| lengthL = cataL (\a b -> 1 + b) 0 | |
| filterL :: (a -> Bool) -> [a] -> [a] | |
| filterL p = cataL (\a b -> if p a then (a:b) else b) [] | |
| -- Fusion Law for Catamorphism | |
| a :: Foldable t => (b -> c) -> (a -> b -> b) -> b -> t a -> c | |
| a z f b = z . foldr f b | |
| --a' :: Foldable t => (b -> c) -> (a -> b -> b) -> b -> t a -> c | |
| --a' z f b = foldr f' b' | |
| -- where f' x y = f x (z y) | |
| -- b' = z b | |
| anaL :: (b -> Bool) -> (b -> (a, b)) -> b -> [a] | |
| anaL p g b = | |
| case p b of | |
| True -> [] | |
| False -> a:(anaL p g b') | |
| where (a, b') = g b | |
| zipL :: (Eq a, Eq b) => ([a], [b]) -> [(a,b)] | |
| zipL = anaL p g | |
| where p (as, bs) = (as == []) || (bs == []) | |
| g ((x:xs), (y:ys)) = ((x,y), (xs, ys)) | |
| iterateL :: (a -> a) -> a -> [a] | |
| iterateL f a = anaL p g a | |
| where p _ = False | |
| g a' = (a', f a') | |
| mapL :: (a -> b) -> [a] -> [b] | |
| mapL f as = anaL p g as | |
| where p xs = length xs == 0 | |
| g (x:xs) = (f x, xs) | |
| hyloL :: c -> (b -> c -> c) -> (a -> (b, a)) -> (a -> Bool) -> a -> c | |
| hyloL c f g p a = | |
| case p a of | |
| True -> c | |
| False -> b `f` (hyloL c f g p a') | |
| where (b, a') = g a | |
| facL = hyloL 1 (*) g p | |
| where g n = (n, n-1) | |
| p n = n == 0 | |
| data Nat = Z | S Nat deriving (Show, Eq) | |
| addNat :: Nat -> Nat -> Nat | |
| addNat Z b = b | |
| addNat (S a) b = S (addNat a b) | |
| multNat :: Nat -> Nat -> Nat | |
| multNat a b = go a b | |
| where go (S Z) y = y | |
| go (S x) y = go x (addNat b y) | |
| go Z y = Z | |
| paraL :: (Nat -> b -> b) -> b -> Nat -> b | |
| paraL f b Z = b | |
| paraL f b (S n) = n `f` (paraL f b n) | |
| paraLFac :: Nat -> Nat | |
| paraLFac = paraL f b | |
| where f n acc = (S n) `multNat` acc | |
| b = S Z | |
| -------------- | |
| -- Functors -- | |
| -------------- | |
| -- a Bifunctor Ϯ is a binary operation taking types into types and | |
| -- functions into functions such that if f ∈ A -> B and g ∈ C -> D | |
| -- fϮg ∈ AϮC -> BϮD, and which preserves identities and composition: | |
| -- | |
| -- idϮid = id | |
| -- fϮg ∘ hϮj = (f ∘ h)Ϯ(g ∘ j) | |
| -- | |
| -- a functor is unary type operation F, which also is an operation on | |
| -- functions, F ∈ (A -> B) -> (Af -> Bf) that preserves identity and | |
| -- composition | |
| class (Bifunctor f) where | |
| bimap :: (a -> b) -> (c -> d) -> f a c -> f b d | |
| -- D||D' = {(d, d')|d ∈ D,d' ∈ D'} | |
| data Product a b = Product a b deriving (Eq, Show) | |
| instance Bifunctor Product where | |
| --bimap f g (Product a b) = Product (f a) (g b) | |
| bimap f g = (f . fst') `tupling` (g . snd') | |
| -- (f||g) (x, x') = (f x, g x') | |
| instance Functor (Product a) where | |
| fmap f pab = bimap id f pab | |
| --- Related Combinators --- | |
| -- Projection | |
| -- `π (x, y) = x | |
| fst' :: Product a b -> a | |
| fst' (Product a b) = a | |
| -- π` (x, y) = y | |
| snd' :: Product a b -> b | |
| snd' (Product a b) = b | |
| -- Tupling | |
| -- (f ∆ g) = (f x, g x) | |
| tupling :: (a -> b) -> (a -> c) -> a -> Product b c | |
| tupling f g = \x -> Product (f x) (g x) | |
| -- D|D' = ({0}||D)U({1}||D')U{⊥} | |
| data Sum a b = A a | B b | Bottom deriving (Eq, Show) | |
| instance Bifunctor Sum where | |
| --bimap f g = (leftInjection . f) `selection` (rightInjection . g) | |
| bimap f _ (A a) = A $ f a | |
| bimap _ g (B b) = B $ g b | |
| bimap _ _ Bottom = Bottom | |
| -- (f|g) ⊥ = ⊥ | |
| -- (f|g) (0, x) = (0, f x) | |
| -- (f|g) (1, x') = (1, f x') | |
| instance Functor (Sum a) where | |
| fmap f sum = bimap id f sum | |
| --- Related Combinators --- | |
| leftInjection :: a -> Sum a b | |
| leftInjection = A | |
| rightInjection :: b -> Sum a b | |
| rightInjection = B | |
| selection :: (a -> c) -> (b -> c) -> Sum a b -> c | |
| selection f g = \x -> case x of | |
| A a -> f a | |
| B b -> g b | |
| newtype Reader r a = Reader { runReader :: r -> a } | |
| instance Bifunctor Reader where | |
| bimap f g (Reader ra) = Reader $ \r -> undefined | |
| instance Functor (Reader r) where | |
| fmap f (Reader ra) = Reader $ \r -> f (ra r) | |
| -- Arrow Function | |
| (.->) f g = \h -> g . h . f | |
| --- Related Combinators --- | |
| curry' :: ((a, b) -> c) -> (a -> b -> c) | |
| curry' f a b = f (a, b) | |
| uncurry' :: (a -> b -> c) -> ((a, b) -> c) | |
| uncurry' f (a, b) = f a b | |
| eval' :: ((a -> b), a) -> b | |
| eval' (f, x) = f x | |
| newtype Identity a = Identity a deriving (Eq, Show) | |
| instance Functor Identity where | |
| fmap f (Identity a) = Identity $ f a | |
| newtype Const a b = Const a deriving (Eq, Show) | |
| instance Functor (Const a) where | |
| fmap f ca = bimap id f ca | |
| instance Bifunctor Const where | |
| bimap f g (Const a) = Const $ f a | |
| -- Lifting | |
| -- For functors F, G and bifunctor Ϯ we define the functors FG and FϮG by: | |
| -- | |
| -- X(FG) = X(F)G | |
| -- X(FϮG) = (XF)Ϯ(XG) | |
| -- | |
| -- For both types and functions X | |
| -- Sectioning | |
| -- ??? | |
| --------------------- | |
| -- Combinator laws -- | |
| --------------------- | |
| instance (Arbitrary a, Arbitrary b) => Arbitrary (Product a b) where | |
| arbitrary = Product <$> arbitrary <*> arbitrary | |
| instance (Arbitrary a, Arbitrary b) => Arbitrary (Sum a b) where | |
| arbitrary = frequency [(1, A <$> arbitrary) | |
| ,(1, B <$> arbitrary)] | |
| instance Arbitrary a => Arbitrary (Identity a) where | |
| arbitrary = Identity <$> arbitrary | |
| instance (Arbitrary a) => Arbitrary (Const a b) where | |
| arbitrary = Const <$> arbitrary | |
| instance (CoArbitrary a, CoArbitrary b) => CoArbitrary (Sum a b) where | |
| coarbitrary (A x) = variant 0 . coarbitrary x | |
| coarbitrary (B y) = variant 1 . coarbitrary y | |
| type F = Int -> Int | |
| type H = Sum Int Int -> Int | |
| -- `π ∘ f||g == f ∘ π | |
| prop (Fn (f :: F)) (Fn (g :: F)) x y = | |
| (fst' . bimap f g) (Product x y) == (f . fst') (Product x y) | |
| prop1 :: (Int -> Int) -> (Int -> Int) -> Int -> Int -> Bool | |
| prop1 f g x y = (fst' . bimap f g) (Product x y) == (f . fst') (Product x y) | |
| -- `π ∘ f ∆ g = f | |
| -- \x.(`π ∘ f ∆ g) x = f x | |
| prop2 x (Fn (f :: Int -> Int)) (Fn (g :: Int -> Int)) = | |
| (fst' . (f `tupling` g)) x == f x | |
| -- π` ∘ f||g == g ∘ π | |
| prop3 (Fn (f :: F)) (Fn (g :: F)) x y = | |
| (snd' . bimap f g) (Product x y) == (g . snd') (Product x y) | |
| -- π` ∘ f ∆ g = g x | |
| -- \x.(π` ∘ f ∆ g) x = g x | |
| prop4 x (Fn (f :: F)) (Fn (g :: F)) = | |
| (snd' . (f `tupling` g)) x == g x | |
| -- TODO: What is the signature of h? It seems like it | |
| -- would have to return a Product. | |
| -- (`π ∘ h) ∆ (π` ∘ h) = h | |
| -- \x.((`π ∘ h) ∆ (π` ∘ h)) x = h x | |
| --prop5 x (Fn (h :: Int -> Int)) = | |
| -- ((fst' . h) `tupling` (snd' . h)) x == h x | |
| -- `π ∆ π` = id | |
| -- \x.(`π ∆ π`) x = id x | |
| prop6 x = (fst' `tupling` snd') x == id x | |
| -- f||g ∘ (h ∆ j) = (f ∘ h) ∆ (g ∘ j) | |
| -- \x.(f||g ∘ (h ∆ j)) x = \x.((f ∘ h) ∆ (g ∘ j)) x | |
| prop7 x (Fn (f :: F)) (Fn (g :: F)) (Fn (h :: F)) (Fn (j :: F)) = | |
| (bimap f g) ((h `tupling` j) x) == ((f . h) `tupling` (g . j)) x | |
| -- f ∆ g ∘ h = (f ∘ h) ∆ (g ∘ h) | |
| -- \x.(f ∆ g ∘ h) x = \x.(f ∘ h) ∆ (g ∘ h)) x | |
| prop8 x (Fn (f :: F)) (Fn (g :: F)) (Fn (h :: F)) = | |
| ((f `tupling` g) . h) x == ((f . h) `tupling` (g . h)) x | |
| -- NOTE: This implication cannot be proven with random testing | |
| -- f||g === h||j = f = h ∧ g = j | |
| -- \x. y.((f||g) x y == (h||j) x y) === \x y.(f x == h x) ^ (g y == j y) | |
| prop9 x y (Fn (f :: F)) (Fn (g :: F)) (Fn (h :: F)) (Fn (j :: F)) = | |
| (bimap f g (Product x y)) == (bimap h j (Product x y)) ==> | |
| f x == h x && g y == j y | |
| -- NOTE: This implication cannot be proven with random testing | |
| -- f ∆ g = h ∆ j === f = h ∧ g = j | |
| -- \x.(f ∆ g = h ∆ j) x === \x.(f x == h x) ^ (g x == j x) | |
| prop10 x (Fn (f :: F)) (Fn (g :: F)) (Fn (h :: F)) (Fn (j :: F)) = | |
| (f `tupling` g $ x ) == (h `tupling` j $ x ) ==> | |
| (f x == h x) && (g x == j x) | |
| -- f|g ∘ `i = `i ∘ f | |
| -- \X.(f|g (X|Y) . (`i X)) = \X.`i ∘ (f X) | |
| prop11 x (Fn (f :: F)) (Fn (g :: F)) = | |
| ((bimap f g) . leftInjection) x == (leftInjection . f) x | |
| -- f ∇ g ∘ `i = f | |
| -- \x. (f ∇ g ∘ `i) x = f x | |
| prop12 x (Fn (f :: F)) (Fn (g :: F)) = | |
| ((f `selection` g) . leftInjection) x == f x | |
| -- f|g ∘ i` = i` ∘ g | |
| -- \X.(f|g (X|Y) . (`i X)) = \X.`i ∘ (f X) | |
| prop13 x (Fn (f :: F)) (Fn (g :: F)) = | |
| ((bimap f g) . rightInjection) x == (rightInjection . g) x | |
| -- f ∇ g ∘ `i = f | |
| -- \x. (f ∇ g ∘ i`) x = g x | |
| prop14 x (Fn (f :: F)) (Fn (g :: F)) = | |
| ((f `selection` g) . rightInjection) x == g x | |
| -- TODO: What does strict mean? | |
| -- TODO: How to use the Sum CoArbitrary Instance | |
| -- (h ∘ `i) ∇ (h ∘ i`) = h <== h strict | |
| prop15 xy (Fn (h :: H)) = | |
| ((h . leftInjection) `selection` (h . rightInjection)) xy | |
| -- `i ∇ i` = id | |
| -- \x.(`i ∇ i`) x = id x | |
| prop16 x = (leftInjection `selection` rightInjection) x == id x | |
| -- f ∇ g ∘ h|j = (f ∘ h) ∇ (g ∘ j) | |
| -- \x.(f ∇ g ∘ h|j) x = ((f ∘ h) ∇ (g ∘ j)) x | |
| prop17 x (Fn (f :: F)) (Fn (g :: F)) (Fn (h :: F)) (Fn (j :: F)) = | |
| ((f `selection` g) . (bimap h j)) x == ((f . h) `selection` (g . j)) x | |
| -- TODO: What does strict mean? | |
| -- f ∘ g ∇ h = (f ∘ g) ∇ (f ∘ h) <== h strict | |
| -- \X|Y.((f ∘ g ∇ h) X|Y) = \X|Y.((f ∘ g) ∇ (f ∘ h)) X|X | |
| prop18 xy (Fn (f :: F)) (Fn (g :: F)) (Fn (h :: F)) = | |
| (f . (g `selection` h)) xy == ((f . g) `selection` (f . h)) xy | |
| -- NOTE: This implication cannot be proven with random testing | |
| -- f|g = h|j === f = h ∧ g = j | |
| -- \X|Y.f|g X|Y = h|j X|Y === f x = h x ∧ g y = j y | |
| prop19 xy (Fn (f :: F)) (Fn (g :: F)) (Fn (h :: F)) (Fn (j :: F)) = | |
| undefined | |
| -- NOTE: This implication cannot be proven with random testing | |
| -- f ∇ g = h ∇ j === f = h ∧ g = j | |
| -- \X|Y.f ∇ g X|Y = h ∇ j X|Y === f x = h x ∧ g y = j y | |
| prop20 xy (Fn (f :: F)) (Fn (g :: F)) (Fn (h :: F)) (Fn (j :: F)) = | |
| undefined | |
| ----------- | |
| -- Varia -- | |
| ----------- | |
| -- p ∈ A -> Bool | |
| -- p? ∈ A -> A|A | |
| -- p? a = ⊥, p a = ⊥ | |
| -- = `i a, p a = true | |
| -- = i` a, p a = false | |
| pq :: (a -> Bool) -> a -> Sum a a | |
| pq p a = | |
| case p a of | |
| True -> leftInjection a | |
| False -> rightInjection a | |
| propVaria1 x (Fn (f :: F)) (Fn (g :: F)) (Fn (p :: Int -> Bool)) = | |
| ((f `selection` g) . (pq p)) x == if p x then f x else g x | |
| void _ = () | |
| propVaria2 x (Fn (f :: F)) = (void . f) x == void x | |
| -- p? ∘ x = x|x ∘ (p ∘ x)? | |
| propVaria3 x (Fn (f :: Int -> Int)) (Fn (p :: Int -> Bool)) = | |
| (((pq p) . f) x) == ((bimap f f) . ((pq (p . f)))) x | |
| -- In order to make recursion explicit, we use: | |
| -- µ ∈ (A -> A) -> A | |
| -- µ f = x where x = f x | |
| u :: (a -> a) -> a | |
| u f = x where x = f x | |
| -- Least Fixed Point Recursion Example: | |
| len xs = if xs == [] then 0 else 1 + len (tail xs) | |
| len' :: Eq a => [a] -> Int | |
| len' = u (\rec xs -> if xs == [] then 0 else 1 + rec (tail xs)) | |
| ----------------------------- | |
| -- Natural Transformations -- | |
| ----------------------------- | |
| -- let F and G be functors and φA ∈ AF -> AG for any type A. | |
| -- φA is a polymorphic function. A Natural Transformation | |
| -- is a family of functions φA such that: | |
| -- ∀f: f ∈ A -> B: φB ∘ fF = fG ∘ φA | |
| f :: x -> y | |
| f = undefined | |
| fF :: Functor f => f x -> f y | |
| fF = fmap f | |
| fG :: Functor g => g x -> g y | |
| fG = fmap f | |
| nat :: (Functor f, Functor g) => f a -> g a | |
| nat = undefined | |
| data Id a = Id a deriving (Show, Functor) | |
| data Yd a = Yd a deriving (Show, Functor) | |
| natId :: Id a -> Yd a | |
| natId (Id a) = Yd a | |
| natYd :: Yd a -> Id a | |
| natYd (Yd a) = Id a | |
| -- Let F be a monofunctor | |
| -- Let L be a type | |
| -- inF ∈ LF -> L | |
| -- outF ∈ L -> LF | |
| --in' :: List' a (List a) -> List a | |
| --in' Nil' = Nil | |
| --in' (Cons' a x) = Cons a x | |
| --out' :: List a -> Fixable (List a) (List a) | |
| --out' Nil = Nil' | |
| --out' (Cons a as) = Cons' a as | |
| -- NOTE: What is the left arrow here? | |
| -- id = µ (in <- out) | |
| -- µF denotes the pair (L, in) | |
| -- µF is the least fixed point of F | |
| -- Using the fixed point to define a recursive list: | |
| -- XL = 1|(A||X) | |
| -- (A*, in) = µL | |
| -------------------------------- | |
| ---- Haskell Implementation ---- | |
| -------------------------------- | |
| newtype Fix f = Fix { unFix :: f (Fix f) } deriving (Generic, Typeable) | |
| fix :: (a -> a) -> a | |
| fix f = let x = f x in x | |
| genCata :: Functor f => (f a -> a) -> (Fix f -> a) | |
| genCata alg = alg . fmap (genCata alg) . unFix | |
| genAna :: Functor f => (a -> f a) -> a -> Fix f | |
| genAna coAlg = Fix . fmap (genAna coAlg) . coAlg | |
| genHylo :: Functor f => (f b -> b) -> (a -> f a) -> a -> b | |
| genHylo phi psi = genCata phi . genAna psi | |
| ---------------------- | |
| ---- List Example ---- | |
| ---------------------- | |
| -- type List a = Fix (ListF a) | |
| data List a = Nil | Cons a (List a) | |
| data ListF a x = NilF | ConsF a x deriving Functor | |
| fromL :: [a] -> Fix (ListF a) | |
| fromL = foldr (\a b -> Fix (ConsF a b)) (Fix NilF) | |
| toList :: Fix (ListF a) -> [a] | |
| toList = | |
| genCata (\xs -> case xs of | |
| NilF -> [] | |
| ConsF a as -> a : as) | |
| listLengthAlg :: Num p => ListF a p -> p | |
| listLengthAlg x = | |
| case x of | |
| NilF -> 0 | |
| (ConsF _ n) -> n + 1 | |
| listLengthCata :: Num a => [a] -> a | |
| listLengthCata = genCata listLengthAlg . fromL | |
| listSumAlg :: Num p => ListF p p -> p | |
| listSumAlg x = | |
| case x of | |
| NilF -> 0 | |
| (ConsF a r) -> a + r | |
| listSumCata :: Num a => [a] -> a | |
| listSumCata = genCata listSumAlg . fromL | |
| listFilterAlg :: (a -> Bool) -> ListF a [a] -> [a] | |
| listFilterAlg p x = | |
| case x of | |
| NilF -> [] | |
| (ConsF a r) -> if p a then (a:r) else r | |
| listFilterCata :: (a -> Bool) -> [a] -> [a] | |
| listFilterCata p = genCata (listFilterAlg p) . fromL | |
| listFoldAlg :: Monoid a => ListF a a -> a | |
| listFoldAlg x = | |
| case x of | |
| NilF -> mempty | |
| (ConsF a r) -> a `mappend` r | |
| listFoldCata :: Monoid a => [a] -> a | |
| listFoldCata = genCata listFoldAlg . fromL | |
| listFoldrAlg :: (a -> b -> b) -> b -> ListF a b -> b | |
| listFoldrAlg f b x = | |
| case x of | |
| NilF -> b | |
| (ConsF a r) -> f a r | |
| listFoldrCata :: (a -> b -> b) -> b -> [a] -> b | |
| listFoldrCata f b = genCata (listFoldrAlg f b) . fromL | |
| listMapAlg :: (a -> b) -> ListF a [b] -> [b] | |
| listMapAlg f x = | |
| case x of | |
| NilF -> [] | |
| (ConsF a r) -> (f a):r | |
| listMapCata :: (a -> b) -> [a] -> [b] | |
| listMapCata f = genCata (listMapAlg f) . fromL | |
| ----------------------------- | |
| ---- Binary Tree Example ---- | |
| ----------------------------- | |
| --type BinTree a = Fix (BinTreeF a) | |
| data BinTree a = Leaf | Branch (BinTree a) a (BinTree a) deriving Show | |
| data BinTreeF a x = LeafF | BranchF x a x deriving Functor | |
| fromT :: BinTree a -> Fix (BinTreeF a) | |
| fromT Leaf = Fix LeafF | |
| fromT (Branch l a r) = Fix (BranchF (fromT l) a (fromT r)) | |
| toT :: Fix (BinTreeF a) -> BinTree a | |
| toT = | |
| genCata (\tree -> case tree of | |
| LeafF -> Leaf | |
| BranchF l a r -> Branch l a r) | |
| treeSumAlg :: Num a => BinTreeF a a -> a | |
| treeSumAlg x = | |
| case x of | |
| LeafF -> 0 | |
| BranchF l a r -> l + a + r | |
| treeSumCata :: Num a => BinTree a -> a | |
| treeSumCata = genCata treeSumAlg . fromT | |
| -- TODO: Implement Factor Tree anamorphism | |
| factorTreeCoAlg :: [Integer] -> Integer -> BinTreeF Integer Integer | |
| factorTreeCoAlg primes 0 = LeafF | |
| factorTreeCoAlg primes 1 = LeafF | |
| factorTreeCoAlg primes n | |
| | n `elem` primes = LeafF | |
| | otherwise = BranchF left n right | |
| where left = case find (\a -> n `mod` a == 0 && n /= a) primes of | |
| Just x' -> x' | |
| Nothing -> 1 | |
| right = n `div` right | |
| factorTreeAna n = toT . genAna (factorTreeCoAlg primes) $ n | |
| where primes = takeWhileS (\x -> x <= (n `div` 2)) $ sieveAna [2..] | |
| factorTree :: Integer -> BinTree Integer | |
| factorTree 0 = Leaf | |
| factorTree 1 = Leaf | |
| factorTree n = Branch left n right | |
| where primes = takeWhileS (\x -> x <= n) $ sieveAna [2..] | |
| p = case find (\a -> n `mod` a == 0 && n /= a) primes of | |
| Just x' -> x' | |
| Nothing -> 1 | |
| left = if p == 1 then Leaf else Branch Leaf p Leaf | |
| right = if n `elem` primes then Leaf else (factorTree $ n `div` p) | |
| data FactorTree = | |
| Prime Integer | |
| | Composite FactorTree Integer FactorTree | |
| deriving Show | |
| factorTree' :: Integer -> FactorTree | |
| factorTree' n | |
| | n `elem` primes = Prime n | |
| | otherwise = Composite (Prime left) n right | |
| where primes = takeWhileS (\x -> x <= n) $ sieveAna [2..] | |
| left = case find (\a -> n `mod` a == 0 && n /= a) primes of | |
| Just x' -> x' | |
| Nothing -> 1 | |
| right = factorTree' $ n `div` left | |
| ------------------------------ | |
| ---- General Tree Example ---- | |
| ------------------------------ | |
| -- type GenTree a = Fix (GenTreeF a) | |
| data GenTree a = GenLeaf | GenBranch a [GenTree a] deriving Show | |
| data GenTreeF a x = GenLeafF | GenBranchF a [x] deriving Functor | |
| toGT :: Fix (GenTreeF a) -> GenTree a | |
| toGT = | |
| genCata (\tree -> case tree of | |
| GenLeafF -> GenLeaf | |
| GenBranchF x xs -> GenBranch x xs) | |
| fromGT :: GenTree a -> Fix (GenTreeF a) | |
| fromGT GenLeaf = Fix GenLeafF | |
| fromGT (GenBranch x xs) = Fix (GenBranchF x (fmap fromGT xs)) | |
| genTreeSumAlg :: Num a => GenTreeF a a -> a | |
| genTreeSumAlg x = | |
| case x of | |
| GenLeafF -> 0 | |
| GenBranchF x xs -> x + sum xs | |
| genTreeSumCata :: Num a => GenTree a -> a | |
| genTreeSumCata = genCata genTreeSumAlg . fromGT | |
| ------------------------ | |
| ---- Stream Example ---- | |
| ------------------------ | |
| data Stream a = Stream a (Stream a) deriving Show | |
| --type Stream a = Fix (SteamF a) | |
| data StreamF a x = StreamF a x deriving Functor | |
| -- TODO: Rewrite take and takeWhile using recursion schemes: | |
| takeS :: Int -> Stream a -> [a] | |
| takeS 0 s = [] | |
| takeS n (Stream a as) = a : (takeS (n-1) as) | |
| takeWhileS :: (a -> Bool) -> Stream a -> [a] | |
| takeWhileS p (Stream a as) = | |
| case p a of | |
| True -> a:(takeWhileS p as) | |
| False -> [] | |
| fromS :: Stream a -> Fix (StreamF a) | |
| fromS (Stream a as) = Fix (StreamF a (fromS as)) | |
| toS :: Fix (StreamF a) -> Stream a | |
| toS = genCata (\(StreamF a x) -> Stream a x) | |
| countCoAlg :: Integer -> StreamF Integer Integer | |
| countCoAlg n = StreamF n (n+1) | |
| fibCoAlg :: (Integer, Integer) -> StreamF (Integer, Integer) (Integer, Integer) | |
| fibCoAlg (n, m) = StreamF (n, m) ((m, m + n)) | |
| sieveCoAlg :: [Integer] -> StreamF Integer [Integer] | |
| sieveCoAlg (p:ps) = StreamF p (filter (\x -> x `mod` p /= 0) ps) | |
| countAna :: Integer -> Stream Integer | |
| countAna = toS . genAna countCoAlg | |
| fibAna :: (Integer, Integer) -> Stream (Integer, Integer) | |
| fibAna = toS . genAna fibCoAlg | |
| -- TODO: Test performance of sievaAna | |
| sieveAna :: [Integer] -> Stream Integer | |
| sieveAna = toS . genAna sieveCoAlg |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment