Skip to content

Commit d45e652

Browse files
authored
Update benchmarks (#103)
* Update benchmarks for 5.2.0 * Add benchmarks build to Travis * Fix typos * benchmarks -> benchmark * Update README and commits.
1 parent f6e493a commit d45e652

File tree

10 files changed

+436
-144
lines changed

10 files changed

+436
-144
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@
55
/node_modules/
66
/output/
77
package-lock.json
8+
/tmp/

.travis.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ script:
1515
- bower install --production
1616
- npm run -s build
1717
- bower install
18+
- npm run -s build:benchmark
1819
- npm -s test
1920
after_success:
2021
- >-

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ Module documentation is [published on Pursuit](http://pursuit.purescript.org/pac
2222

2323
## Benchmarks
2424

25-
The following benchmarks compare the current implementation with the implementation at `v0.6.1` (purescript/purescript-free@0df59c5d459fed983131856886fc3a4b43234f1f), which used the `Gosub` technique to defer monadic binds.
25+
The following benchmarks compare the implementation at `v5.2.0` (commit f686f5fc07766f3ca9abc83b47b6ad3da326759a) with the implementation at `v0.6.1` (commit 0df59c5d459fed983131856886fc3a4b43234f1f), which used the `Gosub` technique to defer monadic binds.
2626

2727
![left-bind-small](benchmark/left-bind-small.png)
2828

benchmark/Benchmark/Free0df59c5.purs

Lines changed: 61 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,22 @@
11
module Benchmark.Free0df59c5
2-
( Free(..), GosubF()
2+
( Free(..)
3+
, GosubF
34
, FreeC(..)
4-
, MonadFree, wrap
5-
, Natural()
6-
, liftF, liftFI, liftFC, liftFCI
7-
, pureF, pureFC
8-
, mapF, mapFC
9-
, bindF, bindFC
10-
, injF, injFC
5+
, class MonadFree
6+
, wrap
7+
, Natural
8+
, liftF
9+
, liftFI
10+
, liftFC
11+
, liftFCI
12+
, pureF
13+
, pureFC
14+
, mapF
15+
, mapFC
16+
, bindF
17+
, bindFC
18+
, injF
19+
, injFC
1120
, runFree
1221
, runFreeM
1322
, runFreeC
@@ -16,18 +25,15 @@ module Benchmark.Free0df59c5
1625

1726
import Prelude
1827

19-
import Data.Exists
20-
21-
import Control.Monad.Trans
22-
import Control.Monad.Eff
23-
import Control.Monad.Rec.Class
24-
25-
import Data.Identity
26-
import Data.Coyoneda
27-
import Data.Either
28-
import Data.Function
29-
import Data.Maybe
30-
import Data.Inject (Inject, inj)
28+
import Control.Monad.Rec.Class (class MonadRec, Step(..), tailRecM)
29+
import Control.Monad.Trans.Class (class MonadTrans)
30+
import Data.Coyoneda (Coyoneda, hoistCoyoneda, liftCoyoneda, lowerCoyoneda)
31+
import Data.Either (Either(..), either)
32+
import Data.Exists (Exists, mkExists, runExists)
33+
import Data.Functor.Coproduct.Inject (class Inject, inj)
34+
import Data.Identity (Identity(..))
35+
import Data.Newtype (unwrap)
36+
import Partial.Unsafe (unsafePartialBecause)
3137

3238
type Natural f g = forall a. f a -> g a
3339

@@ -54,43 +60,43 @@ type FreeC f = Free (Coyoneda f)
5460
class MonadFree f m where
5561
wrap :: forall a. f (m a) -> m a
5662

57-
instance functorFree :: (Functor f) => Functor (Free f) where
63+
instance functorFree :: Functor f => Functor (Free f) where
5864
map f (Pure a) = Pure (f a)
5965
map f g = liftA1 f g
6066

61-
instance applyFree :: (Functor f) => Apply (Free f) where
67+
instance applyFree :: Functor f => Apply (Free f) where
6268
apply = ap
6369

64-
instance applicativeFree :: (Functor f) => Applicative (Free f) where
70+
instance applicativeFree :: Functor f => Applicative (Free f) where
6571
pure = Pure
6672

67-
instance bindFree :: (Functor f) => Bind (Free f) where
73+
instance bindFree :: Functor f => Bind (Free f) where
6874
bind (Gosub g) k = runExists (\(GosubF v) -> gosub v.a (\x -> gosub (\unit -> v.f x) k)) g
6975
bind a k = gosub (\unit -> a) k
7076

71-
instance monadFree :: (Functor f) => Monad (Free f)
77+
instance monadFree :: Functor f => Monad (Free f)
7278

7379
instance monadTransFree :: MonadTrans Free where
7480
lift f = Free $ do
7581
a <- f
76-
return (Pure a)
82+
pure (Pure a)
7783

78-
instance monadFreeFree :: (Functor f) => MonadFree f (Free f) where
84+
instance monadFreeFree :: Functor f => MonadFree f (Free f) where
7985
wrap = Free
8086

81-
instance monadRecFree :: (Functor f) => MonadRec (Free f) where
87+
instance monadRecFree :: Functor f => MonadRec (Free f) where
8288
tailRecM f u = f u >>= \o -> case o of
83-
Left a -> tailRecM f a
84-
Right b -> pure b
89+
Loop a -> tailRecM f a
90+
Done b -> pure b
8591

8692
-- | Lift an action described by the generating functor `f` into the monad `m`
8793
-- | (usually `Free f`).
88-
liftF :: forall f m a. (Functor f, Monad m, MonadFree f m) => f a -> m a
94+
liftF :: forall f m a. Functor f => Monad m => MonadFree f m => f a -> m a
8995
liftF = wrap <<< map pure
9096

9197
-- | Lift an action described by the generating type constructor `f` into
9298
-- | `Free g` using `Inject` to go from `f` to `g`.
93-
liftFI :: forall f g a. (Inject f g, Functor g) => f a -> Free g a
99+
liftFI :: forall f g a. Inject f g => Functor g => f a -> Free g a
94100
liftFI fa = liftF (inj fa :: g a)
95101

96102
-- | Lift an action described by the generating type constructor `f` into the monad
@@ -100,42 +106,42 @@ liftFC = liftF <<< liftCoyoneda
100106

101107
-- | Lift an action described by the generating type constructor `f` into
102108
-- | `FreeC g` using `Inject` to go from `f` to `g`.
103-
liftFCI :: forall f g a. (Inject f g) => f a -> FreeC g a
109+
liftFCI :: forall f g a. Inject f g => f a -> FreeC g a
104110
liftFCI fa = liftFC (inj fa :: g a)
105111

106112
-- | An implementation of `pure` for the `Free` monad.
107-
pureF :: forall f a. (Applicative f) => a -> Free f a
113+
pureF :: forall f a. Applicative f => a -> Free f a
108114
pureF = Free <<< pure <<< Pure
109115

110116
-- | An implementation of `pure` for the `FreeC` monad.
111-
pureFC :: forall f a. (Applicative f) => a -> FreeC f a
117+
pureFC :: forall f a. Applicative f => a -> FreeC f a
112118
pureFC = liftFC <<< pure
113119

114120
-- | Use a natural transformation to change the generating functor of a `Free` monad.
115-
mapF :: forall f g a. (Functor f, Functor g) => Natural f g -> Free f a -> Free g a
121+
mapF :: forall f g a. Functor f => Functor g => Natural f g -> Free f a -> Free g a
116122
mapF t fa = either (\s -> Free <<< t $ mapF t <$> s) Pure (resume fa)
117123

118124
-- | Use a natural transformation to change the generating type constructor of
119125
-- | a `FreeC` monad to another functor.
120-
mapFC :: forall f g a. (Functor g) => Natural f g -> FreeC f a -> Free g a
121-
mapFC t = mapF (liftCoyonedaTF t)
126+
mapFC :: forall f g a. Functor g => Natural f g -> FreeC f a -> Free g a
127+
mapFC t = mapF (lowerCoyoneda <<< hoistCoyoneda t)
122128

123129
-- | Use a natural transformation to interpret one `Free` monad as another.
124-
bindF :: forall f g a. (Functor f, Functor g) => Free f a -> Natural f (Free g) -> Free g a
130+
bindF :: forall f g a. Functor f => Functor g => Free f a -> Natural f (Free g) -> Free g a
125131
bindF fa t = either (\m -> t m >>= \fa' -> bindF fa' t) Pure (resume fa)
126132

127133
-- | Use a natural transformation to interpret a `FreeC` monad as a different
128134
-- | `Free` monad.
129-
bindFC :: forall f g a. (Functor g) => FreeC f a -> Natural f (Free g) -> Free g a
130-
bindFC fa t = bindF fa (liftCoyonedaTF t)
135+
bindFC :: forall f g a. Functor g => FreeC f a -> Natural f (Free g) -> Free g a
136+
bindFC fa t = bindF fa (lowerCoyoneda <<< hoistCoyoneda t)
131137

132138
-- | Embed computations in one `Free` monad as computations in the `Free` monad for
133139
-- | a coproduct type constructor.
134140
-- |
135141
-- | This construction allows us to write computations which are polymorphic in the
136142
-- | particular `Free` monad we use, allowing us to extend the functionality of
137143
-- | our monad later.
138-
injF :: forall f g a. (Functor f, Functor g, Inject f g) => Free f a -> Free g a
144+
injF :: forall f g a. Functor f => Functor g => Inject f g => Free f a -> Free g a
139145
injF = mapF inj
140146

141147
-- | Embed computations in one `FreeC` monad as computations in the `FreeC` monad for
@@ -144,18 +150,18 @@ injF = mapF inj
144150
-- | This construction allows us to write computations which are polymorphic in the
145151
-- | particular `Free` monad we use, allowing us to extend the functionality of
146152
-- | our monad later.
147-
injFC :: forall f g a. (Inject f g) => FreeC f a -> FreeC g a
148-
injFC = mapF (liftCoyonedaT inj)
153+
injFC :: forall f g a. Inject f g => FreeC f a -> FreeC g a
154+
injFC = mapF (hoistCoyoneda inj)
149155

150-
resume :: forall f a. (Functor f) => Free f a -> Either (f (Free f a)) a
156+
resume :: forall f a. Functor f => Free f a -> Either (f (Free f a)) a
151157
resume f = case f of
152158
Pure x -> Right x
153159
Free x -> Left x
154-
g -> case resumeGosub g of
160+
g -> unsafePartialBecause "Existing implementation." case resumeGosub g of
155161
Left l -> Left l
156162
Right r -> resume r
157163
where
158-
resumeGosub :: Free f a -> Either (f (Free f a)) (Free f a)
164+
resumeGosub :: Partial => Free f a -> Either (f (Free f a)) (Free f a)
159165
resumeGosub (Gosub g) =
160166
runExists (\(GosubF v) -> case v.a unit of
161167
Pure a -> Right (v.f a)
@@ -164,23 +170,23 @@ resume f = case f of
164170

165171
-- | `runFree` runs a computation of type `Free f a`, using a function which unwraps a single layer of
166172
-- | the functor `f` at a time.
167-
runFree :: forall f a. (Functor f) => (f (Free f a) -> Free f a) -> Free f a -> a
168-
runFree fn = runIdentity <<< runFreeM (Identity <<< fn)
173+
runFree :: forall f a. Functor f => (f (Free f a) -> Free f a) -> Free f a -> a
174+
runFree fn = unwrap <<< runFreeM (Identity <<< fn)
169175

170176
-- | `runFreeM` runs a compuation of type `Free f a` in any `Monad` which supports tail recursion.
171177
-- | See the `MonadRec` type class for more details.
172-
runFreeM :: forall f m a. (Functor f, MonadRec m) => (f (Free f a) -> m (Free f a)) -> Free f a -> m a
178+
runFreeM :: forall f m a. Functor f => MonadRec m => (f (Free f a) -> m (Free f a)) -> Free f a -> m a
173179
runFreeM fn = tailRecM \f ->
174180
case resume f of
175-
Left fs -> Left <$> fn fs
176-
Right a -> return (Right a)
181+
Left fs -> Loop <$> fn fs
182+
Right a -> pure (Done a)
177183

178184
-- | `runFreeC` is the equivalent of `runFree` for type constructors transformed with `Coyoneda`,
179185
-- | hence we have no requirement that `f` be a `Functor`.
180-
runFreeC :: forall f a. (forall a. f a -> a) -> FreeC f a -> a
181-
runFreeC nat = runIdentity <<< runFreeCM (Identity <<< nat)
186+
runFreeC :: forall f a. (forall b. f b -> b) -> FreeC f a -> a
187+
runFreeC nat = unwrap <<< runFreeCM (Identity <<< nat)
182188

183189
-- | `runFreeCM` is the equivalent of `runFreeM` for type constructors transformed with `Coyoneda`,
184190
-- | hence we have no requirement that `f` be a `Functor`.
185191
runFreeCM :: forall f m a. (MonadRec m) => Natural f m -> FreeC f a -> m a
186-
runFreeCM nat = runFreeM (liftCoyonedaTF nat)
192+
runFreeCM nat = runFreeM (lowerCoyoneda <<< hoistCoyoneda nat)

0 commit comments

Comments
 (0)