obfusk 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|