forked from UnkindPartition/freemonad-benchmark
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathFused.hs
128 lines (96 loc) · 3.55 KB
/
Fused.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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
{-# LANGUAGE EmptyCase, RankNTypes, GADTs, UndecidableInstances, FlexibleContexts, TypeOperators #-} -- to enable 'forall' keyword
module Fused (run, run', Codensity, State, StateCarrier(..), TermAlgebra(..), Void, Free) where
import Base
import Control.Applicative
import Control.Monad
import Control.Monad.State.Class
import GHC.Generics
run' :: Codensity (StateCarrier Int (Free Void)) a -> Int -> a
run' = fmap runFree . run
run :: (Monad m, TermAlgebra m f) => Codensity (StateCarrier s m) a -> s -> m a
run = unSC . flip runCodensity var
data State s a where
Get :: (s -> a) -> State s a
Put :: s -> a -> State s a
getState :: TermAlgebra f (State s :+: g) => Codensity f s
getState = con (L1 (Get pure))
putState :: TermAlgebra f (State s :+: g) => s -> Codensity f ()
putState s = con (L1 (Put s (pure ())))
genState :: (Monad m, TermAlgebra m f) => a -> (s -> m a)
genState x = const (var x)
algState :: (Monad m, TermAlgebra m f) => State s (s -> m a) -> (s -> m a)
algState (Put s k) _ = k s
algState (Get k) s = k s s
instance Functor (State s) where
fmap f (Get k) = (Get (f . k))
fmap f (Put s a) = (Put s (f a))
{-# INLINE fmap #-}
newtype StateCarrier s m a = SC { unSC :: s -> m a }
instance (Monad m, TermAlgebra m f) => TermAlgebra (StateCarrier s m) (State s :+: f) where
con = SC . (algState \/ conState) . fmap unSC
{-# INLINE con #-}
var = SC . genState
{-# INLINE var #-}
instance TermAlgebra f (State s :+: g) => MonadState s (Codensity f) where
get = getState
put s = putState s
class Functor f => TermAlgebra h f | h -> f where
var :: a -> h a
con :: f (h a) -> h a
data Free f a = Var a | Con (f (Free f a))
instance Functor f => Monad (Free f) where
return = pure
{-# INLINE return #-}
Var a >>= f = f a
Con m >>= f = Con ((>>= f) <$> m)
{-# INLINE (>>=) #-}
instance Functor f => Applicative (Free f) where
pure = Var
{-# INLINE pure #-}
Var a <*> Var b = Var $ a b
Var a <*> Con mb = Con $ fmap a <$> mb
Con ma <*> b = Con $ (<*> b) <$> ma
{-# INLINE (<*>) #-}
instance Functor f => Functor (Free f) where
fmap f = go where
go (Var a) = Var (f a)
go (Con fa) = Con (go <$> fa)
{-# INLINE fmap #-}
instance Functor f => TermAlgebra (Free f) f where
var = Var
{-# INLINE var #-}
con = Con
{-# INLINE con #-}
data Void a
instance Functor Void where
fmap f a = case a of {}
{-# INLINE fmap #-}
runFree :: Free Void a -> a
runFree = fold undefined id
fold alg gen (Var x) = gen x
fold alg gen (Con op) = alg (fmap (fold alg gen) op)
conState :: (Functor g, TermAlgebra m g) => g (s -> m a) -> (s -> m a)
conState op s = con (fmap (\m -> m s) op)
(\/) :: (f b -> b) -> (g b -> b) -> ((f :+: g) b -> b)
(\/) algF algG (L1 s) = algF s
(\/) algF algG (R1 s) = algG s
instance TermAlgebra h f => TermAlgebra (Codensity h) f where
var = return
{-# INLINE var #-}
con = alg_cod con
{-# INLINE con #-}
alg_cod :: Functor f => (forall x. f (h x) -> h x) -> (f (Codensity h a) -> Codensity h a)
alg_cod alg = \op -> Codensity (\k -> alg (fmap (flip runCodensity k) op))
-- Could as well use Control.Monad.Copdensity from kan-extensions, except
-- that it has instances that overlap with the one for MonadState above.
newtype Codensity f a = Codensity {
runCodensity :: forall b. (a -> f b) -> f b
}
instance Functor (Codensity f) where
fmap f m = Codensity (\k -> runCodensity m (k. f))
instance Applicative (Codensity f) where
pure = return
(<*>) = ap
instance Monad (Codensity f) where
return a = Codensity (\k -> k a)
c >>= f = Codensity (\k -> runCodensity c (\a -> runCodensity (f a) k))