monadt 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/lib/monadt/adt.rb +33 -0
- data/lib/monadt/either.rb +35 -0
- data/lib/monadt/list.rb +17 -0
- data/lib/monadt/maybe.rb +51 -0
- data/lib/monadt/monad.rb +43 -0
- data/lib/monadt/reader.rb +16 -0
- data/lib/monadt/reader_state_either.rb +24 -0
- data/lib/monadt/state.rb +16 -0
- data/lib/monadt.rb +49 -0
- metadata +53 -0
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
|
data/lib/monadt/list.rb
ADDED
@@ -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
|
+
|
data/lib/monadt/maybe.rb
ADDED
@@ -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
|
+
|
data/lib/monadt/monad.rb
ADDED
@@ -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,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
|
data/lib/monadt/state.rb
ADDED
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: []
|