obfusk 0.1.1 → 0.1.2
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 +4 -4
- data/README.md +25 -11
- data/lib/obfusk/adt.rb +52 -17
- data/lib/obfusk/atom.rb +44 -0
- data/lib/obfusk/lazy.rb +3 -2
- data/lib/obfusk/list.rb +17 -15
- data/lib/obfusk/monad.rb +9 -3
- data/lib/obfusk/monads.rb +124 -32
- data/lib/obfusk/version.rb +2 -2
- data/lib/obfusk.rb +1 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4c4bd6bb10352b9c18b779e647b5acfd1c3877db
|
4
|
+
data.tar.gz: c6f6309c765f5c519e155286323bbbb9d82590ff
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a4dbae8abf373e372b28bbba4b913e2afcc6045c0f4a2480dc8164fabcdbeaee09685530075828bf2b35de45ba62145c7f7b5f2d0769d5141edbd2cbf4b611e4
|
7
|
+
data.tar.gz: d404720017b40471a4c8abf19ccf6e2ee5261fbe1f43d3763e88992d027b5af3148911a0f6a92ec171917c293087aa33276e16d4ad66bcef68bb53dd55e1152f
|
data/README.md
CHANGED
@@ -2,10 +2,10 @@
|
|
2
2
|
|
3
3
|
File : README.md
|
4
4
|
Maintainer : Felix C. Stegerman <flx@obfusk.net>
|
5
|
-
Date : 2014-06-
|
5
|
+
Date : 2014-06-18
|
6
6
|
|
7
7
|
Copyright : Copyright (C) 2014 Felix C. Stegerman
|
8
|
-
Version : v0.1.
|
8
|
+
Version : v0.1.2
|
9
9
|
|
10
10
|
[]: }}}1
|
11
11
|
|
@@ -27,10 +27,23 @@ class Foo
|
|
27
27
|
constructor :Baz, :value
|
28
28
|
end
|
29
29
|
|
30
|
-
x = Foo.Bar
|
30
|
+
x = Foo.Bar
|
31
31
|
y = Foo.Baz 99
|
32
32
|
|
33
|
-
|
33
|
+
y.value # => 99
|
34
|
+
|
35
|
+
x.match Bar: -> (_) { "it's a bar!" },
|
36
|
+
Baz: -> (z) { "it's a baz with value: #{z.value}" }
|
37
|
+
# => "it's a bar!"
|
38
|
+
```
|
39
|
+
|
40
|
+
```ruby
|
41
|
+
require 'obfusk/atom'
|
42
|
+
|
43
|
+
x = Obfusk.atom 42
|
44
|
+
x._ # => 42
|
45
|
+
10.times { x.swap! { |v| v + 1 } }
|
46
|
+
x._ # => 53
|
34
47
|
```
|
35
48
|
|
36
49
|
```ruby
|
@@ -67,7 +80,7 @@ require 'obfusk/monad'
|
|
67
80
|
|
68
81
|
class Foo
|
69
82
|
include Obfusk::Monad
|
70
|
-
def self.
|
83
|
+
def self.mreturn(x)
|
71
84
|
# ...
|
72
85
|
end
|
73
86
|
def self.bind_pass(m, &b)
|
@@ -78,20 +91,21 @@ end
|
|
78
91
|
f = -> x { '...' }
|
79
92
|
g = -> y { '...' }
|
80
93
|
|
81
|
-
Foo.
|
94
|
+
Foo.new('...').pipeline f, g
|
82
95
|
```
|
83
96
|
|
84
97
|
```ruby
|
85
98
|
require 'obfusk/monads'
|
99
|
+
ms = Obfusk::Monads
|
86
100
|
|
87
|
-
x =
|
88
|
-
y =
|
101
|
+
x = ms.Nothing
|
102
|
+
y = ms.Just 42
|
89
103
|
|
90
104
|
x.bind(y)
|
91
|
-
# =>
|
105
|
+
# => ms.Nothing
|
92
106
|
|
93
|
-
|
94
|
-
|
107
|
+
ms.Left "oops"
|
108
|
+
ms.Right 37
|
95
109
|
```
|
96
110
|
|
97
111
|
...
|
data/lib/obfusk/adt.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
#
|
3
3
|
# File : obfusk/adt.rb
|
4
4
|
# Maintainer : Felix C. Stegerman <flx@obfusk.net>
|
5
|
-
# Date : 2014-06-
|
5
|
+
# Date : 2014-06-17
|
6
6
|
#
|
7
7
|
# Copyright : Copyright (C) 2014 Felix C. Stegerman
|
8
8
|
# Licence : LGPLv3+
|
@@ -17,6 +17,8 @@ module Obfusk
|
|
17
17
|
|
18
18
|
# Algebraic Data Type
|
19
19
|
module ADT
|
20
|
+
module Constructor; end
|
21
|
+
|
20
22
|
include Comparable
|
21
23
|
|
22
24
|
def self.included(base)
|
@@ -30,13 +32,24 @@ module Obfusk
|
|
30
32
|
end
|
31
33
|
|
32
34
|
module ClassMethods
|
35
|
+
# record constructor; call with name of constructor and hash of
|
36
|
+
# keys to values
|
37
|
+
def new(*a, &b)
|
38
|
+
ancestors.include?(::Obfusk::ADT::Constructor) ? super : _new(*a, &b)
|
39
|
+
end
|
40
|
+
|
41
|
+
def _new(ctor, data = {}, &b)
|
42
|
+
c = constructors[ctor]
|
43
|
+
c[:method].call *data.values_at(*c[:keys]), &b
|
44
|
+
end
|
45
|
+
|
33
46
|
# duplicate constructors for subclasses
|
34
47
|
def inherited(subclass)
|
35
48
|
return if ::Obfusk::ADT_Meta__[:inheriting].last
|
36
49
|
ctors = constructors
|
37
50
|
subclass.class_eval do
|
38
51
|
ctors.each_pair do |k,v|
|
39
|
-
constructor v[:
|
52
|
+
constructor v[:name], *v[:keys], &v[:block]
|
40
53
|
end
|
41
54
|
end
|
42
55
|
end
|
@@ -56,17 +69,17 @@ module Obfusk
|
|
56
69
|
end
|
57
70
|
end
|
58
71
|
ctor.class_eval do
|
59
|
-
|
60
|
-
keys_.each { |k| define_method(k) {
|
72
|
+
include ::Obfusk::ADT::Constructor
|
73
|
+
keys_.each { |k| define_method(k) { __adt_data__[k] } }
|
61
74
|
define_method(:initialize) do |guard, ctor, *values, &f|
|
62
75
|
raise ArgumentError, 'for internal use only!' \
|
63
76
|
unless guard == :for_internal_use_only
|
64
77
|
if !b && (k = keys_.length) != (v = values.length)
|
65
78
|
raise ArgumentError, "wrong number of arguments (#{v} for #{k})"
|
66
79
|
end
|
67
|
-
data = Hash[keys_.zip values]
|
80
|
+
data = Hash[keys_.zip values].freeze
|
68
81
|
@ctor = ctor ; @ctor_name = name_ ; @ctor_keys = keys_
|
69
|
-
@data = b ? b[self, data, values, f] : data
|
82
|
+
@data = b ? b[self, data, values, f].freeze : data
|
70
83
|
end
|
71
84
|
end
|
72
85
|
class_eval do
|
@@ -81,8 +94,8 @@ module Obfusk
|
|
81
94
|
define_method(name_) { |*values,&b| f[values,b] }
|
82
95
|
end
|
83
96
|
constructors[name_] = {
|
84
|
-
ctor: ctor, method: method(name_),
|
85
|
-
|
97
|
+
ctor: ctor, method: method(name_), name: name_,
|
98
|
+
keys: keys_, block: b
|
86
99
|
}
|
87
100
|
end
|
88
101
|
name_
|
@@ -95,11 +108,11 @@ module Obfusk
|
|
95
108
|
end
|
96
109
|
|
97
110
|
# import the constructors into another namespace
|
98
|
-
def import_constructors(scope)
|
111
|
+
def import_constructors(scope, const = true)
|
99
112
|
constructors.each_pair do |k,v|
|
100
113
|
m = method k
|
101
114
|
scope.define_singleton_method(k) { |*a,&b| m[*a,&b] }
|
102
|
-
scope.const_set k, v[:ctor]
|
115
|
+
scope.const_set k, v[:ctor] if const
|
103
116
|
end
|
104
117
|
end
|
105
118
|
|
@@ -113,8 +126,27 @@ module Obfusk
|
|
113
126
|
end
|
114
127
|
end
|
115
128
|
|
129
|
+
# clone
|
130
|
+
def clone(merge_data = {})
|
131
|
+
merge_data.empty? ? self :
|
132
|
+
self.class.superclass.new(__adt_ctor_name__,
|
133
|
+
__adt_data__.merge(merge_data))
|
134
|
+
end
|
135
|
+
|
136
|
+
def __adt_ctor__
|
137
|
+
@ctor
|
138
|
+
end
|
139
|
+
|
140
|
+
def __adt_ctor_name__
|
141
|
+
@ctor_name
|
142
|
+
end
|
143
|
+
|
144
|
+
def __adt_ctor_keys__
|
145
|
+
@ctor_keys
|
146
|
+
end
|
147
|
+
|
116
148
|
# the data
|
117
|
-
def
|
149
|
+
def __adt_data__
|
118
150
|
@data
|
119
151
|
end
|
120
152
|
|
@@ -122,7 +154,7 @@ module Obfusk
|
|
122
154
|
def ==(rhs)
|
123
155
|
rhs.is_a?(::Obfusk::ADT) &&
|
124
156
|
self.class.superclass == rhs.class.superclass &&
|
125
|
-
|
157
|
+
__adt_ctor__ == rhs.__adt_ctor__ && _eq_data(rhs)
|
126
158
|
end
|
127
159
|
|
128
160
|
# equal and of the same type?
|
@@ -135,16 +167,18 @@ module Obfusk
|
|
135
167
|
return nil unless rhs.is_a?(::Obfusk::ADT) &&
|
136
168
|
self.class.superclass == rhs.class.superclass
|
137
169
|
k = self.class.superclass.constructors.keys
|
138
|
-
|
170
|
+
__adt_ctor__ != rhs.__adt_ctor__ ?
|
171
|
+
k.index(__adt_ctor_name__) <=> k.index(rhs.__adt_ctor_name__) :
|
139
172
|
_compare_data(rhs)
|
140
173
|
end
|
141
174
|
|
142
175
|
def _eq_data(rhs)
|
143
|
-
|
176
|
+
__adt_data__ == rhs.__adt_data__
|
144
177
|
end
|
145
178
|
|
146
179
|
def _compare_data(rhs)
|
147
|
-
|
180
|
+
__adt_data__.values_at(*__adt_ctor_keys__) <=>
|
181
|
+
rhs.__adt_data__.values_at(*__adt_ctor_keys__)
|
148
182
|
end
|
149
183
|
|
150
184
|
# pattern matching
|
@@ -154,12 +188,13 @@ module Obfusk
|
|
154
188
|
raise ArgumentError,
|
155
189
|
"constructors do not match (#{ok} for #{ck})"
|
156
190
|
end
|
157
|
-
opts[
|
191
|
+
opts[__adt_ctor_name__][self]
|
158
192
|
end
|
159
193
|
|
160
194
|
# to string
|
161
195
|
def to_s
|
162
|
-
|
196
|
+
n = self.class.superclass.name || '#ADT'
|
197
|
+
"#<#{n}.#{__adt_ctor_name__}: #{__adt_data__}>"
|
163
198
|
end
|
164
199
|
|
165
200
|
# to string
|
data/lib/obfusk/atom.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
# -- ; {{{1
|
2
|
+
#
|
3
|
+
# File : obfusk/atom.rb
|
4
|
+
# Maintainer : Felix C. Stegerman <flx@obfusk.net>
|
5
|
+
# Date : 2014-06-16
|
6
|
+
#
|
7
|
+
# Copyright : Copyright (C) 2014 Felix C. Stegerman
|
8
|
+
# Licence : LGPLv3+
|
9
|
+
#
|
10
|
+
# -- ; }}}1
|
11
|
+
|
12
|
+
require 'thread'
|
13
|
+
|
14
|
+
module Obfusk
|
15
|
+
class Atom
|
16
|
+
attr_reader :value
|
17
|
+
alias :_ :value
|
18
|
+
alias :deref :value
|
19
|
+
|
20
|
+
# new Atom with value
|
21
|
+
def initialize(value)
|
22
|
+
@mutex = Mutex.new
|
23
|
+
@value = value
|
24
|
+
end
|
25
|
+
|
26
|
+
# calls block with value; uses a mutex to synchronize
|
27
|
+
def with_value(&b)
|
28
|
+
@mutex.synchronize { b[value] }
|
29
|
+
end
|
30
|
+
|
31
|
+
# atomically swaps the value to be `b[oldvalue]`; uses
|
32
|
+
# `with_value`
|
33
|
+
def swap!(&b)
|
34
|
+
with_value { |v| @value = b[v] }
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# create an Atom
|
39
|
+
def self.atom(value)
|
40
|
+
Atom.new value
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# vim: set tw=70 sw=2 sts=2 et fdm=marker :
|
data/lib/obfusk/lazy.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
#
|
3
3
|
# File : obfusk/lazy.rb
|
4
4
|
# Maintainer : Felix C. Stegerman <flx@obfusk.net>
|
5
|
-
# Date : 2014-06-
|
5
|
+
# Date : 2014-06-17
|
6
6
|
#
|
7
7
|
# Copyright : Copyright (C) 2014 Felix C. Stegerman
|
8
8
|
# Licence : LGPLv3+
|
@@ -16,7 +16,8 @@ module Obfusk
|
|
16
16
|
f = b ? b : -> { x }; v = nil; e = false
|
17
17
|
g = -> () { unless e then v = f[]; e = true end; v }
|
18
18
|
g.define_singleton_method(:__obfusk_lazy__?) { true }
|
19
|
-
g.define_singleton_method(:_)
|
19
|
+
g.define_singleton_method(:_) { g[] }
|
20
|
+
g.define_singleton_method(:deref) { g[] }
|
20
21
|
g.define_singleton_method(:chain) do |m,*a,&b|
|
21
22
|
::Obfusk::lazy { g[].public_send(m,*a,&b) }
|
22
23
|
end
|
data/lib/obfusk/list.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
#
|
3
3
|
# File : obfusk/list.rb
|
4
4
|
# Maintainer : Felix C. Stegerman <flx@obfusk.net>
|
5
|
-
# Date : 2014-06-
|
5
|
+
# Date : 2014-06-17
|
6
6
|
#
|
7
7
|
# Copyright : Copyright (C) 2014 Felix C. Stegerman
|
8
8
|
# Licence : LGPLv3+
|
@@ -22,8 +22,10 @@ module Obfusk
|
|
22
22
|
|
23
23
|
constructor :Nil
|
24
24
|
constructor(:Cons, :head, :tail) do |cls, data, values, f|
|
25
|
-
|
26
|
-
|
25
|
+
# count block as extra value; count nil tail as missing one
|
26
|
+
v = values.length + (f ? 1 : 0) -
|
27
|
+
(values.length > 1 && !data[:tail] ? 1 : 0)
|
28
|
+
if (k = cls.__adt_ctor_keys__.length) != v
|
27
29
|
raise ArgumentError, "wrong number of arguments (#{v} for #{k})"
|
28
30
|
end
|
29
31
|
{ head: data[:head], tail: f ? ::Obfusk.lazy(&f) :
|
@@ -81,16 +83,16 @@ module Obfusk
|
|
81
83
|
# the list of those elements that satisfy the predicate
|
82
84
|
def filter(p = nil, &b)
|
83
85
|
g = p || b
|
84
|
-
match Nil: -> (_)
|
85
|
-
Cons: -> (
|
86
|
-
|
86
|
+
match Nil: -> (_) { Nil() },
|
87
|
+
Cons: -> (_) { g[head] ? Cons(head) { tail.filter(g) }
|
88
|
+
: tail.filter(g) }
|
87
89
|
end
|
88
90
|
|
89
91
|
# the list obtained by applying a function (or block) to each element
|
90
92
|
def map(f = nil, &b)
|
91
93
|
g = f || b
|
92
|
-
match Nil: -> (_)
|
93
|
-
Cons: -> (
|
94
|
+
match Nil: -> (_) { Nil() },
|
95
|
+
Cons: -> (_) { Cons(g[head]) { tail.map g } }
|
94
96
|
end
|
95
97
|
|
96
98
|
# --
|
@@ -123,8 +125,8 @@ module Obfusk
|
|
123
125
|
|
124
126
|
# append two lists
|
125
127
|
def append(ys)
|
126
|
-
match Nil: -> (_)
|
127
|
-
Cons: -> (
|
128
|
+
match Nil: -> (_) { ys._ },
|
129
|
+
Cons: -> (_) { Cons(head) { tail.append ys } }
|
128
130
|
end
|
129
131
|
|
130
132
|
# def reverse
|
@@ -146,8 +148,8 @@ module Obfusk
|
|
146
148
|
# operator is lazy and must be treated as such.
|
147
149
|
def foldr(z, f = nil, &b)
|
148
150
|
g = f || b
|
149
|
-
match Nil: -> (_)
|
150
|
-
Cons: -> (
|
151
|
+
match Nil: -> (_) { z },
|
152
|
+
Cons: -> (_) { g[head, tail.chain(:foldr, z, g)] }
|
151
153
|
end
|
152
154
|
|
153
155
|
# def foldr1
|
@@ -189,8 +191,8 @@ module Obfusk
|
|
189
191
|
# the prefix of length n (or the list itself if n > length)
|
190
192
|
def take(n)
|
191
193
|
return Nil() if n <= 0
|
192
|
-
match Nil: -> (_)
|
193
|
-
Cons: -> (
|
194
|
+
match Nil: -> (_) { Nil() },
|
195
|
+
Cons: -> (_) { Cons(head) { tail.take(n - 1) } }
|
194
196
|
end
|
195
197
|
|
196
198
|
# def drop
|
@@ -238,7 +240,7 @@ module Obfusk
|
|
238
240
|
# TODO
|
239
241
|
# def self.bind_pass(m, &b)
|
240
242
|
# m.match Nil: -> (_) { m },
|
241
|
-
# Cons: -> (
|
243
|
+
# Cons: -> (_) {} # concat (map f m)
|
242
244
|
# end
|
243
245
|
end
|
244
246
|
|
data/lib/obfusk/monad.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
#
|
3
3
|
# File : obfusk/monad.rb
|
4
4
|
# Maintainer : Felix C. Stegerman <flx@obfusk.net>
|
5
|
-
# Date : 2014-06-
|
5
|
+
# Date : 2014-06-16
|
6
6
|
#
|
7
7
|
# Copyright : Copyright (C) 2014 Felix C. Stegerman
|
8
8
|
# Licence : LGPLv3+
|
@@ -40,7 +40,8 @@ module Obfusk
|
|
40
40
|
# bind m, k # discard value
|
41
41
|
# ```
|
42
42
|
def bind(m, k = nil, &b)
|
43
|
-
b ? bind_pass(m, &b) :
|
43
|
+
b ? bind_pass(m, &b) : k.is_a?(::Proc) ? bind_pass(m, &k) :
|
44
|
+
bind_discard(m, k)
|
44
45
|
end
|
45
46
|
|
46
47
|
# sequentially compose two actions, passing any value produced
|
@@ -71,7 +72,8 @@ module Obfusk
|
|
71
72
|
|
72
73
|
# concatenate a sequence of binds
|
73
74
|
def pipeline(m, *fs)
|
74
|
-
|
75
|
+
a = -> f, x { f.is_a?(::Proc) ? f[x] : f }
|
76
|
+
fs.empty? ? m : m.bind { |x| pipeline a[fs.first,x], *fs.drop(1) }
|
75
77
|
end
|
76
78
|
|
77
79
|
# evaluate each action in the sequence from left to right, and
|
@@ -94,6 +96,10 @@ module Obfusk
|
|
94
96
|
self.class.public_send m, self, *a, &b
|
95
97
|
end
|
96
98
|
end
|
99
|
+
|
100
|
+
def >>(k)
|
101
|
+
bind k
|
102
|
+
end
|
97
103
|
end
|
98
104
|
|
99
105
|
module MonadPlus
|
data/lib/obfusk/monads.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
#
|
3
3
|
# File : obfusk/monads.rb
|
4
4
|
# Maintainer : Felix C. Stegerman <flx@obfusk.net>
|
5
|
-
# Date : 2014-06-
|
5
|
+
# Date : 2014-06-17
|
6
6
|
#
|
7
7
|
# Copyright : Copyright (C) 2014 Felix C. Stegerman
|
8
8
|
# Licence : LGPLv3+
|
@@ -13,48 +13,140 @@ require 'obfusk/adt'
|
|
13
13
|
require 'obfusk/monad'
|
14
14
|
|
15
15
|
module Obfusk
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
16
|
+
module Monads
|
17
|
+
class Identity
|
18
|
+
include ADT
|
19
|
+
include Monad
|
20
20
|
|
21
|
-
|
22
|
-
constructor :Just, :value
|
21
|
+
constructor :Identity, :run
|
23
22
|
|
24
|
-
|
25
|
-
|
23
|
+
def self.mreturn(x)
|
24
|
+
Identity(x)
|
25
|
+
end
|
26
|
+
def self.bind_pass(m, &b)
|
27
|
+
b[m.run]
|
28
|
+
end
|
26
29
|
end
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
30
|
+
|
31
|
+
class Maybe
|
32
|
+
include ADT
|
33
|
+
include Monad
|
34
|
+
include MonadPlus
|
35
|
+
|
36
|
+
constructor :Nothing
|
37
|
+
constructor :Just, :value
|
38
|
+
|
39
|
+
def self.mreturn(x)
|
40
|
+
Just(x)
|
41
|
+
end
|
42
|
+
def self.bind_pass(m, &b)
|
43
|
+
m.match Nothing: -> (_) { Nothing() },
|
44
|
+
Just: -> (x) { b[x.value] }
|
45
|
+
end
|
46
|
+
def self.zero
|
47
|
+
Nothing()
|
48
|
+
end
|
49
|
+
def self.lazy_plus(m, k)
|
50
|
+
m.match Nothing: -> (_) { k._ },
|
51
|
+
Just: -> (_) { m }
|
52
|
+
end
|
37
53
|
end
|
38
|
-
end
|
39
54
|
|
40
|
-
|
41
|
-
|
42
|
-
|
55
|
+
class Either
|
56
|
+
include ADT
|
57
|
+
include Monad
|
43
58
|
|
44
|
-
|
45
|
-
|
59
|
+
constructor :Left , :value
|
60
|
+
constructor :Right, :value
|
46
61
|
|
47
|
-
|
48
|
-
|
62
|
+
def self.mreturn(x)
|
63
|
+
Right(x)
|
64
|
+
end
|
65
|
+
def self.bind_pass(m, &b)
|
66
|
+
m.match Left: -> (_) { m },
|
67
|
+
Right: -> (x) { b[x.value] }
|
68
|
+
end
|
49
69
|
end
|
50
|
-
|
51
|
-
|
52
|
-
|
70
|
+
|
71
|
+
class State
|
72
|
+
include ADT
|
73
|
+
include Monad
|
74
|
+
|
75
|
+
class Pair
|
76
|
+
include ADT
|
77
|
+
constructor :Pair, :value, :state
|
78
|
+
end
|
79
|
+
|
80
|
+
Pair.import_constructors self, false
|
81
|
+
|
82
|
+
constructor :State, :run
|
83
|
+
|
84
|
+
# construct a state monad computation from a function (or block)
|
85
|
+
def self.state(f = nil, &b)
|
86
|
+
State f || b
|
87
|
+
end
|
88
|
+
|
89
|
+
# evaluate response with the given initial state and return the
|
90
|
+
# final value, discarding the final state
|
91
|
+
def self.eval(m, s)
|
92
|
+
m.run[s].value
|
93
|
+
end
|
94
|
+
|
95
|
+
# evaluate response with the given initial state and return the
|
96
|
+
# final state, discarding the final value
|
97
|
+
def self.exec(m, s)
|
98
|
+
m.run[s].state
|
99
|
+
end
|
100
|
+
|
101
|
+
# execute action on a state modified by applying a function (or
|
102
|
+
# block)
|
103
|
+
def self.with(m, f = nil, &b)
|
104
|
+
state { |s| m.run[(f || b)[s]] }
|
105
|
+
end
|
106
|
+
|
107
|
+
# get the state
|
108
|
+
def self.get
|
109
|
+
state { |s| Pair s, s }
|
110
|
+
end
|
111
|
+
|
112
|
+
# set the state
|
113
|
+
def self.put(s)
|
114
|
+
state { |_| Pair nil, s }
|
115
|
+
end
|
116
|
+
|
117
|
+
# modify the state by applying a function (or block)
|
118
|
+
def self.modify(f = nil, &b)
|
119
|
+
state { |s| Pair nil, (f || b)[s] }
|
120
|
+
end
|
121
|
+
|
122
|
+
# get a specific component of the state, using a projection
|
123
|
+
# function (or block)
|
124
|
+
def self.gets(f = nil, &b)
|
125
|
+
state { |s| Pair (f || b)[s], s }
|
126
|
+
end
|
127
|
+
|
128
|
+
def self.mreturn(x)
|
129
|
+
state { |s| Pair x, s }
|
130
|
+
end
|
131
|
+
def self.bind_pass(m, &b)
|
132
|
+
state { |s| x = m.run[s]; b[x.value].run[x.state] }
|
133
|
+
end
|
134
|
+
|
135
|
+
%w{ eval exec with }.map(&:to_sym).each do |m|
|
136
|
+
define_method(m) do |*a,&b|
|
137
|
+
self.class.public_send m, self, *a, &b
|
138
|
+
end
|
139
|
+
end
|
53
140
|
end
|
54
|
-
end
|
55
141
|
|
56
|
-
|
142
|
+
[Maybe, Either].each do |x|
|
143
|
+
x.import_constructors self
|
144
|
+
end
|
57
145
|
|
146
|
+
[Identity, State].each do |x|
|
147
|
+
x.import_constructors self, false
|
148
|
+
end
|
149
|
+
end
|
58
150
|
end
|
59
151
|
|
60
152
|
# vim: set tw=70 sw=2 sts=2 et fdm=marker :
|
data/lib/obfusk/version.rb
CHANGED
data/lib/obfusk.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: obfusk
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Felix C. Stegerman
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-06-
|
11
|
+
date: 2014-06-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -65,6 +65,7 @@ files:
|
|
65
65
|
- Rakefile
|
66
66
|
- lib/obfusk.rb
|
67
67
|
- lib/obfusk/adt.rb
|
68
|
+
- lib/obfusk/atom.rb
|
68
69
|
- lib/obfusk/lazy.rb
|
69
70
|
- lib/obfusk/list.rb
|
70
71
|
- lib/obfusk/monad.rb
|