monadt 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c19e86f991142006e0e23f98ec59c2a9780db485
4
+ data.tar.gz: 52cc959d8eeb05fa7d617d51278ec9b2aed00467
5
+ SHA512:
6
+ metadata.gz: a06ffff7277f97c3a16652bbb45ed0d0c13a9ad382772a58d372dbdf9b93e2ae45ce9eafdca7612ed29dffc9a5c1513a4be98d2cae09fb128450e2f5142f91d4
7
+ data.tar.gz: a61dab72be3127c89f11d33ad49af0094838073554719fd2f10de78a6408120302c9818c5843ec71b94c379f43d0348e962dbd5a80591cd545b3e6d6bea23b93
data/lib/monadt/adt.rb ADDED
@@ -0,0 +1,33 @@
1
+ AdtPattern = Struct.new :klass, :lambda
2
+
3
+ def data(*fields)
4
+ base = if fields.size > 0
5
+ Struct.new(*fields)
6
+ else
7
+ Object
8
+ end
9
+ Class.new(base)
10
+ end
11
+
12
+ Default = data
13
+
14
+ module Adt
15
+ def match(o, *cases)
16
+ m = cases.find do |tpl|
17
+ tpl.klass == o.class || tpl.klass == Default
18
+ end
19
+ params =
20
+ if m.lambda.arity > 0
21
+ o.values.take(m.lambda.arity)
22
+ else
23
+ []
24
+ end
25
+ m.lambda.call(*params)
26
+ end
27
+
28
+ def with(klass, prc=nil, &blk)
29
+ AdtPattern.new klass, prc || blk
30
+ end
31
+ end
32
+
33
+
@@ -0,0 +1,35 @@
1
+ require 'monadt/adt'
2
+
3
+ module Monadt
4
+ module Either
5
+ Left = data :left
6
+ Right = data :right
7
+ end
8
+ class Either::Left
9
+ def is_left?() true end
10
+ def is_right?() false end
11
+ def to_s() "Left(#{left})" end
12
+ end
13
+ class Either::Right
14
+ def is_left?() false end
15
+ def is_right?() true end
16
+ def to_s() "Right(#{right})" end
17
+ end
18
+
19
+ class EitherM
20
+ class << self
21
+ include Adt
22
+
23
+ def bind(m, &blk)
24
+ match(m,
25
+ with(Either::Left) { |v| m },
26
+ with(Either::Right) { |v| blk.call(v) })
27
+ end
28
+
29
+ def return(a)
30
+ Either::Right.new a
31
+ end
32
+ end
33
+
34
+ end
35
+ end
@@ -0,0 +1,17 @@
1
+ require_relative 'maybe'
2
+ require_relative 'either'
3
+ require_relative 'state'
4
+ require_relative 'reader_state_either'
5
+
6
+ class ListM
7
+ class << self
8
+ def bind(m, &blk)
9
+ m.flat_map(&blk)
10
+ end
11
+
12
+ def return(a)
13
+ [a]
14
+ end
15
+ end
16
+ end
17
+
@@ -0,0 +1,51 @@
1
+ require 'monadt/adt'
2
+
3
+ module Monadt
4
+ module Maybe
5
+ Just = data :value
6
+ Nothing = data
7
+ end
8
+
9
+ class Maybe::Just
10
+ def is_nothing?() false end
11
+ def to_s() "Just #{value}" end
12
+ end
13
+ class Maybe::Nothing
14
+ def is_nothing?() true end
15
+ def to_s() "Nothing" end
16
+ end
17
+
18
+ class MaybeM
19
+ class << self
20
+ include Adt
21
+
22
+ def bind(m, &blk)
23
+ match(m,
24
+ with(Maybe::Just) { |v| blk.call(v) },
25
+ with(Maybe::Nothing) { m })
26
+ end
27
+
28
+ def return(a)
29
+ Maybe::Just.new a
30
+ end
31
+ end
32
+ end
33
+
34
+ # like Maybe but nil / not-nill
35
+ class PresentM
36
+ class << self
37
+ def bind(m, &blk)
38
+ if m.nil?
39
+ nil
40
+ else
41
+ blk.call(m)
42
+ end
43
+ end
44
+
45
+ def return(a)
46
+ a
47
+ end
48
+ end
49
+ end
50
+ end
51
+
@@ -0,0 +1,43 @@
1
+ module Monadt
2
+ module Internal
3
+ class MonadObj
4
+ def initialize(klass, yielder)
5
+ @yielder = yielder
6
+ @klass = klass
7
+ end
8
+
9
+ def return(val)
10
+ @klass.return val
11
+ end
12
+
13
+ def bind(val)
14
+ @yielder.yield val
15
+ end
16
+ end
17
+ end
18
+
19
+ class Monad
20
+ class << self
21
+ def do_m(klass, &blk)
22
+ e = Enumerator.new do |y|
23
+ m_obj = Internal::MonadObj.new klass, y
24
+ blk.call(m_obj)
25
+ end
26
+ do_m_recur(klass, e)
27
+ end
28
+
29
+ def do_m_recur(klass, e)
30
+ begin
31
+ ma = e.next
32
+ rescue StopIteration => ex
33
+ return ex.result
34
+ end
35
+ klass.bind(ma) do |a|
36
+ e.feed a
37
+ do_m_recur(klass, e)
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+
@@ -0,0 +1,16 @@
1
+ module Monadt
2
+ class ReaderM
3
+ class << self
4
+ def bind(m, &blk)
5
+ ->(e) {
6
+ v = m.(e)
7
+ blk.call(e, v)
8
+ }
9
+ end
10
+
11
+ def return(val)
12
+ ->(e) { val }
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,24 @@
1
+ require 'monadt/adt'
2
+
3
+ module Monadt
4
+ class ReaderStateEitherM
5
+ class << self
6
+ include Adt
7
+
8
+ def bind(m, &blk)
9
+ ->(e, s) {
10
+ c, s2 = m.(e, s)
11
+ match(c,
12
+ with(Either::Left) {|v| [c, s2]},
13
+ with(Either::Right) {|v|
14
+ blk.call(v).(e, s2)
15
+ })
16
+ }
17
+ end
18
+
19
+ def return(val)
20
+ ->(e, s) { [EitherM.return(val), s] }
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,16 @@
1
+ module Monadt
2
+ class StateM
3
+ class << self
4
+ def bind(m, &blk)
5
+ ->(st) {
6
+ v, s = m.(st)
7
+ blk.call(v).(s)
8
+ }
9
+ end
10
+
11
+ def return(val)
12
+ ->(st) { [val, st] }
13
+ end
14
+ end
15
+ end
16
+ end
data/lib/monadt.rb ADDED
@@ -0,0 +1,49 @@
1
+ require 'monadt/maybe'
2
+ require 'monadt/either'
3
+ require 'monadt/state'
4
+ require 'monadt/reader_state_either'
5
+ require 'monadt/monad'
6
+
7
+ module Monadt
8
+ class Monad
9
+ class << self
10
+ def maybe(&blk)
11
+ do_m(MaybeM, &blk)
12
+ end
13
+
14
+ def present(&blk)
15
+ do_m(PresentM, &blk)
16
+ end
17
+
18
+ def either(&blk)
19
+ do_m(EitherM, &blk)
20
+ end
21
+
22
+ def state(&blk)
23
+ do_m(StateM, &blk)
24
+ end
25
+
26
+ def run_state(initial_state, &blk)
27
+ prc = state(&blk)
28
+ prc.(initial_state).first
29
+ end
30
+
31
+ def reader(&blk)
32
+ do_m(ReaderM, &blk)
33
+ end
34
+
35
+ def run_reader(env, &blk)
36
+ reader(&blk).(env)
37
+ end
38
+
39
+ def reader_state_choice(&blk)
40
+ do_m(ReaderStateEitherM, &blk)
41
+ end
42
+
43
+ def run_reader_state_choice(env, initial_state, &blk)
44
+ reader_state_choice(&blk).(env, initial_state).first
45
+ end
46
+ end
47
+ end
48
+ end
49
+
metadata ADDED
@@ -0,0 +1,53 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: monadt
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Will Pleasant-Ryan
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-03-25 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Functions to create ADTs and do pattern matching, as well as Enumerator
14
+ based Monad computation
15
+ email: will.ryan@atomicobject.com
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - lib/monadt.rb
21
+ - lib/monadt/adt.rb
22
+ - lib/monadt/either.rb
23
+ - lib/monadt/list.rb
24
+ - lib/monadt/maybe.rb
25
+ - lib/monadt/monad.rb
26
+ - lib/monadt/reader.rb
27
+ - lib/monadt/reader_state_either.rb
28
+ - lib/monadt/state.rb
29
+ homepage: https://github.com/atomicobject/monadt
30
+ licenses:
31
+ - Apache
32
+ metadata: {}
33
+ post_install_message:
34
+ rdoc_options: []
35
+ require_paths:
36
+ - lib
37
+ required_ruby_version: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ required_rubygems_version: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ requirements: []
48
+ rubyforge_project:
49
+ rubygems_version: 2.4.5
50
+ signing_key:
51
+ specification_version: 4
52
+ summary: ADTs and Monads in Ruby
53
+ test_files: []