Skip to content
This repository was archived by the owner on Oct 4, 2020. It is now read-only.

Commit fea0cdb

Browse files
committed
Make Eff faster and safer
1 parent 296d128 commit fea0cdb

File tree

3 files changed

+90
-13
lines changed

3 files changed

+90
-13
lines changed

package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
},
77
"devDependencies": {
88
"eslint": "^3.17.1",
9-
"pulp": "^10.0.4",
10-
"purescript-psa": "^0.5.0-rc.1",
9+
"pulp": "^11.0.0",
10+
"purescript-psa": "^0.5.1",
1111
"rimraf": "^2.6.1"
1212
}
1313
}

src/Control/Monad/Eff.js

+80-7
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,89 @@
11
"use strict";
22

3-
exports.pureE = function (a) {
4-
return function () {
5-
return a;
3+
// Eff a
4+
// = { () -> a }
5+
// | { () -> a, tag: "PURE", _0 :: a, _1 :: Void }
6+
// | { () -> a, tag: "MAP", _0 :: b -> a, _1 :: Ef b }
7+
// | { () -> a, tag: "APPLY", _0 :: Ef b, _1 :: Ef (b -> a) }
8+
// | { () -> a, tag: "BIND", _0 :: b -> Ef a, _1 :: Ef b }
9+
10+
// Operation a b
11+
// = { tag: "MAP", _0 :: a -> b }
12+
// | { tag: "APPLY", _0 :: Ef a }
13+
// | { tag: "APPLY_FUNC", _0 :: a -> b }
14+
// | { tag: "BIND", _0 :: a -> Ef b }
15+
16+
var PURE = "PURE";
17+
var MAP = "MAP";
18+
var APPLY = "APPLY";
19+
var BIND = "BIND";
20+
var APPLY_FUNC = "APPLY_FUNC";
21+
22+
var runEff = function (inputEff) {
23+
var operations = [];
24+
var eff = inputEff;
25+
var res;
26+
var op;
27+
var tag;
28+
effLoop: for (;;) {
29+
tag = eff.tag;
30+
if (tag !== undefined) {
31+
if (tag === MAP || tag === BIND || tag === APPLY) {
32+
operations.push(eff);
33+
eff = eff._1;
34+
continue;
35+
}
36+
// here `tag === PURE`
37+
res = eff._0;
38+
} else {
39+
res = eff();
40+
}
41+
42+
while ((op = operations.pop())) {
43+
if (op.tag === MAP) {
44+
res = op._0(res);
45+
} else if (op.tag === APPLY_FUNC) {
46+
res = op._0(res);
47+
} else if (op.tag === APPLY) {
48+
eff = op._0;
49+
operations.push({ tag: APPLY_FUNC, _0: res });
50+
continue effLoop;
51+
} else { // op.tag === BIND
52+
eff = op._0(res);
53+
continue effLoop;
54+
}
55+
}
56+
return res;
57+
}
58+
};
59+
60+
var mkEff = function (tag, _0, _1) {
61+
var eff = function eff_() { return runEff(eff_); };
62+
eff.tag = tag;
63+
eff._0 = _0;
64+
eff._1 = _1;
65+
return eff;
66+
};
67+
68+
exports.pureE = function (x) {
69+
return mkEff(PURE, x);
70+
};
71+
72+
exports.mapE = function (f) {
73+
return function (eff) {
74+
return mkEff(MAP, f, eff);
675
};
776
};
877

9-
exports.bindE = function (a) {
78+
exports.applyE = function (effF) {
79+
return function (eff) {
80+
return mkEff(APPLY, eff, effF);
81+
};
82+
};
83+
84+
exports.bindE = function (eff) {
1085
return function (f) {
11-
return function () {
12-
return f(a())();
13-
};
86+
return mkEff(BIND, f, eff);
1487
};
1588
};
1689

src/Control/Monad/Eff.purs

+8-4
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ module Control.Monad.Eff
66
, untilE, whileE, forE, foreachE
77
) where
88

9-
import Control.Applicative (class Applicative, liftA1)
9+
import Control.Applicative (class Applicative)
1010
import Control.Apply (class Apply)
1111
import Control.Bind (class Bind)
12-
import Control.Monad (class Monad, ap)
12+
import Control.Monad (class Monad)
1313

1414
import Data.Functor (class Functor)
1515
import Data.Unit (Unit)
@@ -36,10 +36,14 @@ foreign import kind Effect
3636
foreign import data Eff :: # Effect -> Type -> Type
3737

3838
instance functorEff :: Functor (Eff e) where
39-
map = liftA1
39+
map = mapE
40+
41+
foreign import mapE :: forall e a b. (a -> b) -> Eff e a -> Eff e b
4042

4143
instance applyEff :: Apply (Eff e) where
42-
apply = ap
44+
apply = applyE
45+
46+
foreign import applyE :: forall e a b. Eff e (a -> b) -> Eff e a-> Eff e b
4347

4448
instance applicativeEff :: Applicative (Eff e) where
4549
pure = pureE

0 commit comments

Comments
 (0)