-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfact.hs
115 lines (78 loc) · 2.75 KB
/
fact.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
{-# LANGUAGE TypeOperators #-}
import Data.Functor
data Id x = I { i :: x }
data Const x y = K { k :: x }
data (x :+: y) z = SumL (x z) | SumR (y z)
data (x :*: y) z = Prod (x z) (y z)
data Fix x = In { out :: x (Fix x) }
data Zero
type One = Const ()
instance Functor Id where
fmap = (I .) . (. i)
instance Functor (Const x) where
fmap = const (K . k)
instance (Functor x, Functor y) => Functor (x :+: y) where
f `fmap` (SumL x) = SumL (f `fmap` x)
f `fmap` (SumR y) = SumR (f `fmap` y)
instance (Functor x, Functor y) => Functor (x :*: y) where
f `fmap` (Prod x y) = Prod (f `fmap` x) (f `fmap` y)
appI :: (a -> b) -> Id a -> b
appI = (. i)
appK :: (a -> b) -> Const a c -> b
appK = (. k)
appSum :: (a c -> d, b c -> d) -> (a :+: b) c -> d
(f, _) `appSum` (SumL x) = f x
(_, g) `appSum` (SumR x) = g x
appProd :: (a c -> b c -> d) -> (a :*: b) c -> d
f `appProd` (Prod x y) = f x y
-- Folds and unfolds for "free"!
cata :: Functor f => (f a -> a) -> Fix f -> a
cata f = f . (fmap $ cata f) . out
ana :: Functor f => (a -> f a) -> a -> Fix f
ana f = In . (fmap $ ana f) . f
-- Lfix T. 1 + T
type Nat = Fix (One :+: Id)
showNat :: Nat -> Integer
showNat = cata $ appSum (const 0, appI succ)
readNat :: Integer -> Nat
readNat = ana (\x -> if x == 0 then SumL $ K () else SumR $ I $ pred x)
zero :: Nat
zero = In $ SumL $ K ()
suc :: Nat -> Nat
suc = In . SumR . I
prd :: Nat -> Nat
prd = appSum (const zero, i) . out
plus :: Nat -> Nat -> Nat
plus x = cata $ appSum (const x, appI suc)
mult :: Nat -> Nat -> Nat
mult x = cata $ appSum (const zero, appI (`plus` x))
-- Lfix T. 1 + A x T
type List a = Fix (One :+: (Const a :*: Id))
nil :: List a
nil = In $ SumL $ K ()
cons :: a -> List a -> List a
cons x = In . SumR . Prod (K x) . I
downto1 :: Nat -> List Nat
downto1 = ana (appSum (const $ SumL $ K (), appI (\x -> SumR $ Prod (K $ suc x) (I x))) . out)
prod :: List Nat -> Nat
prod = cata $ appSum (const $ suc zero, appProd (\x y -> (k x) `mult` (i y)))
fact :: Nat -> Nat
fact = prod . downto1
factorial :: Integer -> Integer
factorial = showNat . fact . readNat
-- Can we do rose trees?
-- Sadly, List cannot be made into a functor without some fugly newtype juggling, but [] already is
-- The principle is exactly the same, though.
-- Lfix T. A x List T
type Rose a = Fix (Const a :*: [])
-- ...and voila, our `cata` and `ana` just work.
divtree :: Integer -> Rose Integer
divtree = ana (\n -> Prod (K n) (divisors n))
flatten :: Rose Integer -> [Integer]
flatten = cata $ appProd (\x xs -> k x : concat xs)
divisors :: Integer -> [Integer]
divisors n = [x | x <- [2 .. n `div` 2], n `mod` x == 0]
main = do
putStrLn $ show $ showNat ((readNat 3) `mult` (readNat 7))
putStrLn $ show $ factorial 7
putStrLn $ show $ flatten $ divtree 72