Skip to content

Commit 1699da4

Browse files
committed
Merge pull request #19 from ethul/topic/coproduct-and-inject
Topic/coproduct and inject
2 parents 53c6fd5 + c5231e2 commit 1699da4

File tree

5 files changed

+116
-25
lines changed

5 files changed

+116
-25
lines changed

Gruntfile.js

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,26 +13,36 @@ module.exports = function(grunt) {
1313

1414
pscMake: ["<%=libFiles%>"],
1515
dotPsci: ["<%=libFiles%>"],
16-
docgen: {
16+
pscDocs: {
1717
readme: {
1818
src: "src/**/*.purs",
1919
dest: "README.md"
2020
}
2121
},
2222

2323
psc: {
24-
options: {
25-
main: "Teletype"
26-
},
27-
example: {
24+
teletypeExample: {
25+
options: {
26+
main: "Teletype"
27+
},
2828
src: ["examples/Teletype.purs", "<%=libFiles%>"],
2929
dest: "tmp/Teletype.js"
30+
},
31+
teletypeCoproductExample: {
32+
options: {
33+
main: "TeletypeCoproduct"
34+
},
35+
src: ["examples/TeletypeCoproduct.purs", "<%=libFiles%>"],
36+
dest: "tmp/TeletypeCoproduct.js"
3037
}
3138
},
3239

3340
execute: {
34-
example: {
41+
teletypeExample: {
3542
src: "tmp/Teletype.js"
43+
},
44+
teletypeCoproductExample: {
45+
src: "tmp/TeletypeCoproduct.js"
3646
}
3747
}
3848

@@ -43,6 +53,6 @@ module.exports = function(grunt) {
4353
grunt.loadNpmTasks("grunt-contrib-clean");
4454

4555
grunt.registerTask("example", ["psc", "execute"]);
46-
grunt.registerTask("make", ["pscMake", "dotPsci", "docgen"]);
56+
grunt.registerTask("make", ["pscMake", "dotPsci", "pscDocs"]);
4757
grunt.registerTask("default", ["make"]);
4858
};

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,12 +84,16 @@
8484

8585
goMC :: forall f m a. (Monad m) => Natural f m -> FreeC f a -> m a
8686

87+
injC :: forall f g a. (Inject f g) => FreeC f a -> FreeC g a
88+
8789
iterM :: forall f m a. (Functor f, Monad m) => (forall a. f (m a) -> m a) -> Free f a -> m a
8890

8991
liftF :: forall f m a. (Functor f, Monad m, MonadFree f m) => f a -> m a
9092

9193
liftFC :: forall f a. f a -> FreeC f a
9294

95+
mapF :: forall f g a. (Functor f, Functor g) => Natural f g -> Free f a -> Free g a
96+
9397
pureF :: forall f a. (Applicative f) => a -> Free f a
9498

9599
pureFC :: forall f a. (Applicative f) => a -> FreeC f a

bower.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
"purescript-exists": "~0.1.0",
3030
"purescript-transformers": "~0.3.0",
3131
"purescript-lazy": "~0.1.1",
32-
"purescript-foldable-traversable": "~0.1.4"
32+
"purescript-foldable-traversable": "~0.1.4",
33+
"purescript-coproducts": "~0.1.0",
34+
"purescript-inject": "~0.0.2"
3335
}
3436
}

examples/TeletypeCoproduct.purs

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
module TeletypeCoproduct where
2+
3+
import Control.Apply ((*>))
4+
import Control.Alt ((<|>))
5+
import Control.Monad.Eff (Eff())
6+
import Control.Monad.Free (FreeC(), liftFC, injC, goEffC)
7+
import Data.Coyoneda (Natural())
8+
import Data.Inject (prj)
9+
import Data.Functor.Coproduct (Coproduct())
10+
import Data.Maybe.Unsafe (fromJust)
11+
import Debug.Trace (Trace(), trace)
12+
13+
data Teletype1F a = Print1 String a
14+
15+
type Teletype1 a = FreeC Teletype1F a
16+
17+
print1 :: String -> Teletype1 Unit
18+
print1 a = liftFC $ Print1 a unit
19+
20+
data Teletype2F a = Print2 String a
21+
22+
type Teletype2 a = FreeC Teletype2F a
23+
24+
print2 :: String -> Teletype2 Unit
25+
print2 a = liftFC $ Print2 a unit
26+
27+
data Teletype3F a = Print3 String a
28+
29+
type Teletype3 a = FreeC Teletype3F a
30+
31+
print3 :: String -> Teletype3 Unit
32+
print3 a = liftFC $ Print3 a unit
33+
34+
type TF = Coproduct Teletype1F (Coproduct Teletype2F Teletype3F)
35+
36+
type T a = FreeC TF a
37+
38+
r :: T Unit
39+
r = injC $ print1 "1"
40+
41+
s :: T Unit
42+
s = injC $ print2 "2"
43+
44+
t :: T Unit
45+
t = injC $ print3 "3"
46+
47+
u :: T Unit
48+
u = r *> s *> t
49+
50+
teletype1N :: forall e. Natural Teletype1F (Eff (trace :: Trace | e))
51+
teletype1N (Print1 s a) = const a <$> trace ("teletype1: " ++ s)
52+
53+
teletype2N :: forall e. Natural Teletype2F (Eff (trace :: Trace | e))
54+
teletype2N (Print2 s a) = const a <$> trace ("teletype2: " ++ s)
55+
56+
teletype3N :: forall e. Natural Teletype3F (Eff (trace :: Trace | e))
57+
teletype3N (Print3 s a) = const a <$> trace ("teletype3: " ++ s)
58+
59+
tN :: forall e. Natural TF (Eff (trace :: Trace | e))
60+
tN fa = fromJust$ (teletype1N <$> prj fa) <|>
61+
(teletype2N <$> prj fa) <|>
62+
(teletype3N <$> prj fa)
63+
64+
run :: forall a. T a -> Eff (trace :: Trace) a
65+
run = goEffC tN
66+
67+
main = run u

src/Control/Monad/Free.purs

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ module Control.Monad.Free
44
, MonadFree, wrap
55
, liftF, liftFC
66
, pureF, pureFC
7+
, mapF, injC
78
, iterM
89
, goM, goMC
910
, go
@@ -15,6 +16,7 @@ import Control.Monad.Eff
1516
import Data.Coyoneda
1617
import Data.Either
1718
import Data.Function
19+
import Data.Inject (Inject, inj)
1820

1921
data Free f a = Pure a
2022
| Free (f (Free f a))
@@ -61,6 +63,12 @@ liftFC = liftF <<< liftCoyoneda
6163
pureFC :: forall f a. (Applicative f) => a -> FreeC f a
6264
pureFC = liftFC <<< pure
6365

66+
mapF :: forall f g a. (Functor f, Functor g) => Natural f g -> Free f a -> Free g a
67+
mapF t fa = either (\s -> Free <<< t $ mapF t <$> s) Pure (resume fa)
68+
69+
injC :: forall f g a. (Inject f g) => FreeC f a -> FreeC g a
70+
injC = mapF (liftCoyonedaT inj)
71+
6472
-- Note: can blow the stack!
6573
iterM :: forall f m a. (Functor f, Monad m) => (forall a. f (m a) -> m a) -> Free f a -> m a
6674
iterM _ (Pure a) = return a
@@ -100,23 +108,23 @@ go fn f = case resume f of
100108
Left l -> go fn (fn l)
101109
Right r -> r
102110

103-
foreign import goEffImpl
104-
"function goEffImpl(resume, isRight, fromLeft, fromRight, fn, value) {\
105-
\ return function(){\
106-
\ while (true) {\
107-
\ var r = resume(value);\
108-
\ if (isRight(r)) return fromRight(r);\
109-
\ value = fn(fromLeft(r))();\
110-
\ }\
111-
\ };\
112-
\}" :: forall e f a. Fn6
113-
(Free f a -> Either (f (Free f a)) a)
114-
(Either (f (Free f a)) a -> Boolean)
115-
(Either (f (Free f a)) a -> (f (Free f a)))
116-
(Either (f (Free f a)) a -> a)
117-
(f (Free f a) -> Eff e (Free f a))
118-
(Free f a)
119-
(Eff e a)
111+
foreign import goEffImpl """
112+
function goEffImpl(resume, isRight, fromLeft, fromRight, fn, value) {
113+
return function(){
114+
while (true) {
115+
var r = resume(value);
116+
if (isRight(r)) return fromRight(r);
117+
value = fn(fromLeft(r))();
118+
}
119+
};
120+
}""" :: forall e f a. Fn6
121+
(Free f a -> Either (f (Free f a)) a)
122+
(Either (f (Free f a)) a -> Boolean)
123+
(Either (f (Free f a)) a -> (f (Free f a)))
124+
(Either (f (Free f a)) a -> a)
125+
(f (Free f a) -> Eff e (Free f a))
126+
(Free f a)
127+
(Eff e a)
120128

121129
goEff :: forall e f a. (Functor f) => (f (Free f a) -> Eff e (Free f a)) -> Free f a -> Eff e a
122130
goEff fn f = runFn6 goEffImpl resume isRight unsafeLeft unsafeRight fn f

0 commit comments

Comments
 (0)