Skip to content

Topic/free #4

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 39 commits into from
Jun 3, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
00c2c31
Initial commit
ethul Mar 30, 2014
be30684
Beginning a free monad implementation
ethul Mar 30, 2014
d32017b
Merge branch 'topic/project-bootstrap'
ethul Mar 30, 2014
f7797b5
Small typo and point-free `return`
vendethiel Mar 30, 2014
f25c453
Merge branch 'topic/nami-doc-master'
ethul Mar 30, 2014
f9b3cf3
Updating bower and package files
ethul Mar 30, 2014
1384771
Merge branch 'topic/package-changes'
ethul Mar 30, 2014
885fa4f
Bumping version number to 0.0.1
ethul Mar 30, 2014
4ab13a2
Adding iterM
ethul Apr 5, 2014
8a66e45
Merge branch 'topic/free-functions'
ethul Apr 6, 2014
09a8f0e
Bumping version number to 0.0.2
ethul Apr 6, 2014
891f3c7
Add applicative instance
garyb Apr 6, 2014
fc255e5
Removing trailing whitespace
ethul Apr 7, 2014
0b4e0b7
Merge branch 'topic/applicative-instance'
ethul Apr 7, 2014
32ea508
Bumping version number to 0.0.3
ethul Apr 7, 2014
d2bc103
Updating classes for 0.5.0
garyb Apr 8, 2014
74d53b1
Fix non-termination issue
paf31 Apr 10, 2014
f0889e0
Correcting bower repository URL
ethul Apr 13, 2014
8e279b5
Bumping version number to 0.0.5
ethul Apr 14, 2014
b4bf52b
Updating file extensions and repository location
ethul Apr 25, 2014
ae60fb5
Updating dependencies
ethul Apr 28, 2014
17e4adc
Bumping version number to 0.0.6
ethul Apr 28, 2014
a567371
Merge branch 'topic/updating-dependencies'
ethul Apr 28, 2014
e79902e
Add Gosub constructor and tail recursive `go`
puffnfresh May 15, 2014
c8b4780
Add Control.Monad.Trampoline
puffnfresh May 15, 2014
dd131c0
Updating module documentation
ethul May 15, 2014
3b28cbc
Merge branch 'puffnfresh-trampoline'
ethul May 15, 2014
08e0e97
Bumping version number to 0.0.7
ethul May 15, 2014
da17162
Updating example to use iterM
ethul May 28, 2014
136c7fd
Adding runM and foldMap
ethul May 28, 2014
74d96fa
Updating iterM implementation
ethul May 29, 2014
88d3323
Renaming dist directory
ethul May 29, 2014
31e9ed2
Removing unused files
ethul May 29, 2014
8032d99
Merge branch 'topic/purescript-free' into topic/free
ethul May 29, 2014
497d40b
Updating repository for the addition of Free
ethul May 29, 2014
1db7171
Implementing specialization of go for Eff
ethul Jun 1, 2014
663febf
Merge branch 'topic/iterm-stack-issue' of github.com:purescript-contr…
ethul Jun 1, 2014
a1bf898
Merge branch 'topic/purescript-free' into topic/free
ethul Jun 1, 2014
7e9caf9
Updating the README
ethul Jun 1, 2014
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 15 additions & 7 deletions Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ module.exports = function(grunt) {

"use strict";

grunt.initConfig({
grunt.initConfig({

libFiles: [
"src/**/*.purs",
"bower_components/purescript-*/src/**/*.purs*"
],

clean: ["output", "tmp"],

pscMake: ["<%=libFiles%>"],
dotPsci: ["<%=libFiles%>"],
docgen: {
Expand All @@ -19,7 +19,7 @@ module.exports = function(grunt) {
dest: "README.md"
}
},

psc: {
options: {
main: true
Expand All @@ -39,9 +39,13 @@ module.exports = function(grunt) {
exampleCont: {
src: ["examples/Cont.purs", "<%=libFiles%>"],
dest: "tmp/Cont.js"
},
exampleFree: {
src: ["examples/Free.purs", "<%=libFiles%>"],
dest: "tmp/Free.js"
}
},

execute: {
exampleReader: {
src: "tmp/Reader.js"
Expand All @@ -54,9 +58,12 @@ module.exports = function(grunt) {
},
exampleCont: {
src: "tmp/Cont.js"
},
exampleFree: {
src: "tmp/Free.js"
}
}

});

grunt.loadNpmTasks("grunt-purescript");
Expand All @@ -67,6 +74,7 @@ module.exports = function(grunt) {
grunt.registerTask("exampleState", ["psc:exampleState", "execute:exampleState"]);
grunt.registerTask("exampleWriter", ["psc:exampleWriter", "execute:exampleWriter"]);
grunt.registerTask("exampleCont", ["psc:exampleCont", "execute:exampleCont"]);
grunt.registerTask("exampleFree", ["psc:exampleFree", "execute:exampleFree"]);
grunt.registerTask("examples", ["psc", "execute"]);
grunt.registerTask("make", ["pscMake", "dotPsci", "docgen"]);
grunt.registerTask("default", ["make"]);
Expand Down
82 changes: 82 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,58 @@
runErrorT :: forall e m a. ErrorT e m a -> m (Either e a)


## Module Control.Monad.Free

### Types

data Free f a where
Pure :: a -> Free f a
Free :: f (Free f a) -> Free f a
Gosub :: forall s. (forall r. ({ } -> Free f r) -> (r -> Free f a) -> s) -> s -> Free f a


### Type Classes

class MonadFree f m where
wrap :: forall a. f (m a) -> m a


### Type Class Instances

instance applicativeFree :: (Functor f) => Applicative (Free f)

instance applyFree :: (Functor f) => Apply (Free f)

instance bindFree :: (Functor f) => Bind (Free f)

instance functorFree :: (Functor f) => Functor (Free f)

instance monadFree :: (Functor f) => Monad (Free f)

instance monadFreeFree :: (Functor f) => MonadFree f (Free f)

instance monadTransFree :: MonadTrans Free


### Values

go :: forall f a. (Functor f) => (f (Free f a) -> Free f a) -> Free f a -> a

goEff :: forall e f a. (Functor f) => (f (Free f a) -> Eff e (Free f a)) -> Free f a -> Eff e a

goM :: forall f m a. (Functor f, Monad m) => (f (Free f a) -> m (Free f a)) -> Free f a -> m a

iterM :: forall f m a. (Functor f, Monad m) => (forall a. f (m a) -> m a) -> Free f a -> m a

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

pureF :: forall f a. (Applicative f) => a -> Free f a

resume :: forall f a. (Functor f) => Free f a -> Either (f (Free f a)) a

resumeGosub :: forall f a. (Functor f) => (forall s. (forall r. ({ } -> Free f r) -> (r -> Free f a) -> s) -> s) -> Either (f (Free f a)) (Free f a)


## Module Control.Monad.Identity

### Types
Expand Down Expand Up @@ -386,6 +438,36 @@
withStateT :: forall s m a. (s -> s) -> StateT s m a -> StateT s m a


## Module Control.Monad.Trampoline

### Types

data Delay a where
Delay :: { } -> a -> Delay a

type Trampoline a = Free Delay a


### Type Class Instances

instance delayApplicative :: Applicative Delay

instance delayApply :: Apply Delay

instance delayFunctor :: Functor Delay


### Values

delay :: forall a. ({ } -> a) -> Trampoline a

done :: forall a. a -> Trampoline a

runTrampoline :: forall a. Trampoline a -> a

suspend :: forall a. Trampoline a -> Trampoline a


## Module Control.Monad.Trans

### Type Classes
Expand Down
33 changes: 33 additions & 0 deletions examples/Free.purs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
module Main where

import Control.Monad.Eff
import Control.Monad.Free
import Debug.Trace

data TeletypeF a = PutStrLn String a | GetLine (String -> a)

instance teletypeFFunctor :: Functor TeletypeF where
(<$>) f (PutStrLn s a) = PutStrLn s (f a)
(<$>) f (GetLine k) = GetLine (\s -> f (k s))

type Teletype = Free TeletypeF

putStrLn :: String -> Teletype {}
putStrLn s = liftF $ PutStrLn s {}

getLine :: Teletype String
getLine = liftF $ GetLine (\a -> a)

runF :: forall a. TeletypeF a -> Eff (trace :: Trace) a
runF (PutStrLn s a) = (\_ -> a) <$> trace s
runF (GetLine k) = return $ k "fake input"

run :: forall a. Teletype a -> Eff (trace :: Trace) a
run = goEff runF

echo = do
a <- getLine
putStrLn a
putStrLn "Finished"

main = run $ echo
121 changes: 121 additions & 0 deletions src/Control/Monad/Free.purs
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
module Control.Monad.Free where

import Control.Monad.Trans
import Control.Monad.Eff
import Data.Either

data Free f a = Pure a
| Free (f (Free f a))
| Gosub (forall s. (forall r. ({} -> Free f r) -> (r -> Free f a) -> s) -> s)

class MonadFree f m where
wrap :: forall a. f (m a) -> m a

instance functorFree :: (Functor f) => Functor (Free f) where
(<$>) f (Pure a) = Pure (f a)
(<$>) f g = liftA1 f g

instance applyFree :: (Functor f) => Apply (Free f) where
(<*>) = ap

instance applicativeFree :: (Functor f) => Applicative (Free f) where
pure = Pure

instance bindFree :: (Functor f) => Bind (Free f) where
(>>=) (Gosub g) f = Gosub (\h -> g (\a i -> h a (\x -> Gosub (\j -> j (const (i x)) f))))
(>>=) a f = Gosub (\h -> h (const a) f)

instance monadFree :: (Functor f) => Monad (Free f)

instance monadTransFree :: MonadTrans Free where
lift f = Free $ do
a <- f
return (Pure a)

instance monadFreeFree :: (Functor f) => MonadFree f (Free f) where
wrap = Free

liftF :: forall f m a. (Functor f, Monad m, MonadFree f m) => f a -> m a
liftF fa = wrap $ return <$> fa

pureF :: forall f a. (Applicative f) => a -> Free f a
pureF a = Free (pure (Pure a))

-- Note: can blow the stack!
iterM :: forall f m a. (Functor f, Monad m) => (forall a. f (m a) -> m a) -> Free f a -> m a
iterM _ (Pure a) = return a
iterM k (Free f) = k $ iterM k <$> f
iterM k (Gosub f) = f (\req recv -> iterM k (req {}) >>= (iterM k <<< recv))

-- Note: can blow the stack!
goM :: forall f m a. (Functor f, Monad m) => (f (Free f a) -> m (Free f a)) -> Free f a -> m a
goM k f = case resume f of
Left s -> k s >>= goM k
Right a -> return a

resumeGosub :: forall f a. (Functor f) => (forall s. (forall r. ({} -> Free f r) -> (r -> Free f a) -> s) -> s) -> Either (f (Free f a)) (Free f a)
resumeGosub f = f (\a g ->
case a {} of
Pure a -> Right (g a)
Free t -> Left ((\h -> h >>= g) <$> t)
Gosub h -> Right (h (\b i -> b {} >>= (\x -> i x >>= g)))
)

foreign import resume
"function resume(__dict_Functor) {\
\ return function(__copy__1) {\
\ var _1 = __copy__1;\
\ tco: while (true)\
\ if (_1.ctor === 'Control.Monad.Free.Pure')\
\ return Data_Either.Right(_1.values[0]);\
\ else if (_1.ctor === 'Control.Monad.Free.Free')\
\ return Data_Either.Left(_1.values[0]);\
\ else {\
\ var x = resumeGosub(__dict_Functor)(_1.values[0]);\
\ if (x.ctor === 'Data.Either.Left')\
\ return x;\
\ else {\
\ _1 = x.values[0];\
\ continue tco;\
\ }\
\ }\
\ };\
\}" :: forall f a. (Functor f) => Free f a -> Either (f (Free f a)) a

foreign import go
"function go(__dict_Functor) {\
\ return function(f) {\
\ return function(__copy__1) {\
\ var _1 = __copy__1;\
\ var r;\
\ tco: while (true) {\
\ r = resume(__dict_Functor)(_1);\
\ if (r.ctor === 'Data.Either.Left') {\
\ _1 = f(r.values[0]);\
\ continue tco;\
\ } else\
\ return r.values[0];\
\ }\
\ };\
\ };\
\}" :: forall f a. (Functor f) => (f (Free f a) -> Free f a) -> Free f a -> a

foreign import goEff
"function goEff(__dict_Functor) {\
\ return function(f) {\
\ return function(__copy__1) {\
\ return function(){\
\ var _1 = __copy__1;\
\ var r;\
\ tco: while (true) {\
\ r = resume(__dict_Functor)(_1);\
\ if (r.ctor === 'Data.Either.Left') {\
\ _1 = f(r.values[0])();\
\ continue tco;\
\ } else\
\ return function(){return r.values[0];};\
\ }\
\ };\
\ };\
\ };\
\}" :: forall e f a. (Functor f) => (f (Free f a) -> Eff e (Free f a)) -> Free f a -> Eff e a
28 changes: 28 additions & 0 deletions src/Control/Monad/Trampoline.purs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
module Control.Monad.Trampoline where

import Control.Monad.Free

data Delay a = Delay ({} -> a)

instance delayFunctor :: Functor Delay where
(<$>) f (Delay g) = Delay (const (f (g {})))

instance delayApply :: Apply Delay where
(<*>) (Delay f) (Delay a) = Delay (\{} -> (f {}) (a {}))

instance delayApplicative :: Applicative Delay where
pure a = Delay (\{} -> a)

type Trampoline a = Free Delay a

done :: forall a. a -> Trampoline a
done = Pure

suspend :: forall a. Trampoline a -> Trampoline a
suspend a = Free (Delay (\{} -> a))

delay :: forall a. ({} -> a) -> Trampoline a
delay a = Free (done <$> Delay a)

runTrampoline :: forall a. Trampoline a -> a
runTrampoline = go (\(Delay f) -> f {})