ruff 1.0.1 → 1.1.0

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.
@@ -6,7 +6,7 @@
6
6
  <title>
7
7
  Top Level Namespace
8
8
 
9
- &mdash; Ruff 1.0.0 Documentation
9
+ &mdash; Ruff 1.0.1 Documentation
10
10
 
11
11
  </title>
12
12
 
@@ -100,7 +100,7 @@
100
100
  </div>
101
101
 
102
102
  <div id="footer">
103
- Generated on Thu Oct 3 05:05:04 2019 by
103
+ Generated on Fri Oct 4 13:57:07 2019 by
104
104
  <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
105
105
  0.9.20 (ruby-2.6.4).
106
106
  </div>
data/lib/ruff/handler.rb CHANGED
@@ -13,7 +13,6 @@ class Ruff::Handler
13
13
  #
14
14
  # @example
15
15
  # handler = Handler.new
16
-
17
16
  def initialize
18
17
  @handlers = {}
19
18
  @valh = ->(x) { x }
@@ -24,7 +23,8 @@ class Ruff::Handler
24
23
  # Value handler is the handler for *the result value of the computation*.
25
24
  # For example, `Handler.new.to{|_x| 0}.run { value }` results in `0` .
26
25
  #
27
- # The value handler modifies the result of the call of continuation in effect handlers of the handler.
26
+ # The value handler modifies the result of the call of continuation
27
+ # in effect handlers of the handler.
28
28
  #
29
29
  # @param [Proc<A, B>] fun
30
30
  # value handler
@@ -52,7 +52,6 @@ class Ruff::Handler
52
52
  # # msg>> hello
53
53
  # # msg>> world
54
54
  # # returns !
55
-
56
55
  def to(&fun)
57
56
  @valh = fun
58
57
 
@@ -67,14 +66,14 @@ class Ruff::Handler
67
66
  # a handler to handle `eff`;
68
67
  # First argument of `&fun` is *continuation*, proc object
69
68
  # to go back to the handled computation.
70
- # @return [Handler<A!{Effect<Arg, Ret>, e}, B!{e}>] itself updated with handling `Effect<Arg, Ret>`
69
+ # @return [Handler<A!{Effect<Arg, Ret>, e}, B!{e}>]
70
+ # itself updated with handling `Effect<Arg, Ret>`
71
71
  #
72
72
  # @example
73
73
  # handler.on(Log) {|k, msg|
74
74
  # puts "Logger: #{msg}"
75
75
  # k[]
76
76
  # }
77
-
78
77
  def on(eff, &fun)
79
78
  @handlers[eff.id] = fun
80
79
 
@@ -86,7 +85,8 @@ class Ruff::Handler
86
85
  # @param [Proc<(), A>] prc
87
86
  # a thunk to be handled and returns `A`
88
87
  # @return [B]
89
- # a value modified by value handler `Proc<A, B>` , or returned from the effect handler throwing continuation away
88
+ # a value modified by value handler `Proc<A, B>` ,
89
+ # or returned from the effect handler throwing continuation away
90
90
  #
91
91
  # @example
92
92
  # handler.run {
@@ -103,57 +103,58 @@ class Ruff::Handler
103
103
  # Log.perform 3
104
104
  # }
105
105
  # }
106
-
107
106
  def run(&prc)
108
- co = Fiber.new &prc
109
- continue = nil
110
- rehandles = nil
111
-
112
- handle = lambda { |r|
113
- case r
114
- when Eff
115
- if effh = @handlers[r.id]
116
- effh[continue, *r.args]
117
- else
118
- Fiber.yield Resend.new(r, continue)
119
- end
120
- when Resend then
121
- eff = r.eff
122
- next_k = rehandles.call(r.k)
123
-
124
- if effh = @handlers[eff.id]
125
- effh.call(next_k, *eff.args)
126
- else
127
- Fiber.yield Resend.new(eff, next_k)
128
- end
129
- else
130
- @valh.call(r)
131
- end
132
- }
107
+ co = Fiber.new(&prc)
133
108
 
134
- rehandles = lambda { |k|
135
- newh = self.class.new
136
- def newh.add_handler(id, h)
137
- @handlers[id] = h
138
- end
109
+ continue(co).call(nil)
110
+ end
111
+
112
+ # is also private method.
113
+ def handlers=(handlers)
114
+ @handlers = handlers.dup
115
+ end
139
116
 
140
- @handlers.each do |id, h|
141
- newh.add_handler id, h
117
+ private
118
+
119
+ def continue(co)
120
+ ->(*arg) { handle(co, co.resume(*arg)) }
121
+ end
122
+
123
+ # rubocop:disable Metrics/AbcSize
124
+ def handle(co, r)
125
+ case r
126
+ when Eff
127
+ if (effh = @handlers[r.id])
128
+ effh[continue(co), *r.args]
129
+ else
130
+ Fiber.yield Resend.new(r, continue(co))
142
131
  end
132
+ when Resend then
133
+ eff = r.eff
134
+ next_k = rehandles(co, r.k)
143
135
 
144
- class << newh
145
- undef add_handler
136
+ if (effh = @handlers[eff.id])
137
+ effh.call(next_k, *eff.args)
138
+ else
139
+ Fiber.yield Resend.new(eff, next_k)
146
140
  end
141
+ else
142
+ @valh.call(r)
143
+ end
144
+ end
145
+ # rubocop:enable Metrics/AbcSize
147
146
 
148
- lambda { |*args|
149
- continue.call(newh.run { k.call(*args) })
150
- }
151
- }
147
+ def rehandles(co, k)
148
+ newh = self.class.new
152
149
 
153
- continue = lambda { |*arg|
154
- handle.call(co.resume(*arg))
155
- }
150
+ newh.handlers = @handlers
156
151
 
157
- continue.call(nil)
152
+ lambda { |*args|
153
+ newh
154
+ .to { |v| continue(co).call(v) }
155
+ .run { k.call(*args) }
156
+ }
158
157
  end
158
+
159
+ private_methods :handlers=
159
160
  end
data/lib/ruff/objects.rb CHANGED
@@ -14,7 +14,8 @@ class Ruff::Throws::Eff
14
14
 
15
15
  # creates a new object with `id` and `args`.
16
16
  def initialize(id, args)
17
- @id = id; @args = args
17
+ @id = id
18
+ @args = args
18
19
  end
19
20
  end
20
21
 
@@ -30,6 +31,7 @@ class Ruff::Throws::Resend
30
31
 
31
32
  # creates a new object with `eff` and `k`.
32
33
  def initialize(eff, k)
33
- @eff = eff; @k = k
34
+ @eff = eff
35
+ @k = k
34
36
  end
35
37
  end
data/lib/ruff/standard.rb CHANGED
@@ -1,5 +1,21 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # `Ruff::Standard` provides several pre-defined effect handlers modules.
4
+ # Each module provides `Instance` class to instantiate and handle the indivisual effect instances.
5
+ # @example
6
+ # include Ruff::Standard
7
+ #
8
+ # state1 = State::Instance.new
9
+ # state2 = State::Instance.new
10
+ #
11
+ # state1.with_init(3) {
12
+ # state2.with_init(4) {
13
+ # state2.modify {|s| s + state1.get }
14
+ #
15
+ # puts state1.get #==> 3
16
+ # puts state2.get #==> 7
17
+ # }}
18
+ #
3
19
  module Ruff::Standard end
4
20
 
5
21
  require 'ruff/standard/current_time'
@@ -1,30 +1,57 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # `CurrentTime` provides an effect `CurrentTime.eff` and the implementation returning `Time.now` .
4
+ #
5
+ # The module has an instance of `Instance` and provides its methods as module method.
6
+ # @see Standard::CurrentTime::Instance
3
7
  module Ruff::Standard::CurrentTime
4
8
  class Instance
9
+ # makes a new instance.
5
10
  def initialize
6
11
  @eff = Ruff.instance
7
12
  end
8
13
 
14
+ # is a smart method to invoke the effect operation.
15
+ # @return [Time]
16
+ # with `with` , returns `Time.now`
9
17
  def get
10
18
  @eff.perform
11
19
  end
12
20
 
21
+ # is a handler to interpret the effect invokation as requesting the current time.
22
+ # This handler receives the *request* and returns current time.
23
+ #
24
+ # @param [Proc<(), A>!{CurrentTime.eff, e}] th
25
+ # is a thunk returning `A` with the possibility to invoke effects,
26
+ # including `CurrentTime.eff` .
27
+ #
28
+ # @return [A!{e}]
29
+ # returns `A` , without modification by value handler.
30
+ # But it still has the possibility to invoke effects(`e`).
13
31
  def with(&th)
14
- Ruff.handler.on(@eff) { |k| k[Time.now] }.run &th
32
+ Ruff.handler.on(@eff) { |k| k[Time.now] }.run(&th)
15
33
  end
34
+
35
+ # You can reimplement the handler using this effect instance.
36
+ attr_reader :eff
16
37
  end
17
38
 
18
39
  # ---
19
40
  @inst = Instance.new
41
+ @eff = @inst.eff
20
42
 
43
+ # @see Ruff::Standard::CurrentTime::Instance#get
21
44
  def get
22
45
  @inst.get
23
46
  end
24
47
 
48
+ # @see Ruff::Standard::CurrentTime::Instance#with
25
49
  def with(&th)
26
- @inst.with &th
50
+ @inst.with(&th)
27
51
  end
28
52
 
29
53
  module_function :get, :with
54
+
55
+ # @see Ruff::Standard::CurrentTime::Instance#eff
56
+ attr_reader :eff
30
57
  end
@@ -1,16 +1,36 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # `Defer` provides effects `Defer.eff` ,
4
+ # and the implementation to defer procedures .
5
+ #
6
+ # The module has an instance of `Instance` and provides its methods as module method.
7
+ # @see Standard::Defer::Instance
3
8
  module Ruff::Standard::Defer
4
9
  class Instance
10
+ # makes a new instance.
5
11
  def initialize
6
12
  @eff = Ruff.instance
7
13
  end
8
14
 
15
+ # is a smart method to invoke the effect operation.
16
+ # @param [Proc<(), ()>] prc
17
+ # is deferred, or "registerred", and called on the end of computation.
18
+ # @return [()]
9
19
  def register(&prc)
10
20
  @eff.perform prc
11
21
  end
12
22
 
23
+ # is a handler to interpret the effect invocation as registering a procedure.
24
+ # Registerred procedures are run on the end of computation, by value handler.
25
+ #
26
+ # @param [Proc<(), A>!{Defer.eff, e}] th
27
+ # is a thunk returning `A` with the possibility to invoke effects, including `Defer.eff` .
28
+ #
29
+ # @return [A!{e}]
30
+ # returns `A` , without modification by value handler.
31
+ # But it still has the possibility to invoke effects(`e`).
13
32
  def with(&th)
33
+ # This is a stack to store deferred procedures.
14
34
  procs = []
15
35
 
16
36
  Ruff.handler
@@ -19,22 +39,32 @@ module Ruff::Standard::Defer
19
39
  k[]
20
40
  end
21
41
  .to do |_|
42
+ # Like Go's defer functions, it crashes the thunk by reversed order.
22
43
  procs.reverse_each(&:[])
23
44
  end
24
- .run &th
45
+ .run(&th)
25
46
  end
47
+
48
+ # You can reimplement the handler using this effect instance.
49
+ attr_reader :eff
26
50
  end
27
51
 
28
52
  # ---
29
53
  @inst = Instance.new
54
+ @eff = @inst.eff
30
55
 
56
+ # @see Ruff::Standard::Defer::Instance#register
31
57
  def register(&prc)
32
- @inst.register &prc
58
+ @inst.register(&prc)
33
59
  end
34
60
 
61
+ # @see Ruff::Standard::Defer::Instance#with
35
62
  def with(&th)
36
- @inst.with &th
63
+ @inst.with(&th)
37
64
  end
38
65
 
39
66
  module_function :register, :with
67
+
68
+ # @see Ruff::Standard::Defer::Instance#eff
69
+ attr_reader :eff
40
70
  end
@@ -1,65 +1,120 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'ostruct'
4
+
5
+ # `State` provides effects `State.get` and `State.modify` ,
6
+ # and the implementation of the mutable cell or so-called *state* .
7
+ #
8
+ # The module has an instance of `Instance` and provides its methods as module method.
9
+ # @see Standard::State::Instance
3
10
  module Ruff::Standard::State
4
11
  class Instance
12
+ # makes new instances.
5
13
  def initialize
6
- @get = Ruff.instance
7
- @modify = Ruff.instance
14
+ get = Ruff.instance
15
+ modify = Ruff.instance
16
+
17
+ # delegates effect instances
18
+ @eff = OpenStruct.new(get: get, modify: modify)
8
19
  end
9
20
 
21
+ # is a smart method to invoke the effect operation `State.get` .
22
+ # @return [S]
23
+ # with `with` , returns `S` , the current state.
10
24
  def get
11
- @get.perform
25
+ @eff.get.perform
12
26
  end
13
27
 
28
+ # is a smart hetmod to invoke the effect operation `State.modify` .
29
+ # @param [Proc<S, U>] fn
30
+ # is the function to modify the state `S` to `U` .
31
+ # This function has an argument receiving the state.
32
+ # @return [()]
14
33
  def modify(&fn)
15
- @modify.perform fn
34
+ @eff.modify.perform fn
16
35
  end
17
36
 
37
+ # is a short hand for `modify {|_| s }`
38
+ # @param [S] s
39
+ # is the new state.
40
+ # @return [()]
18
41
  def put(s)
19
- @modify.perform ->(_) { s }
42
+ @eff.modify.perform ->(_) { s }
20
43
  end
21
44
 
22
- def with_init(init, &task)
45
+ # is a handler to interpret the effect invocations like *state monad* .
46
+ #
47
+ # @param [S] init
48
+ # is the initial state.
49
+ # @param [Proc<(), A!{State.get, State.modify,, e}>] th
50
+ # is a thunk returning `A` with the possibility to invoke effects,
51
+ # including `State.get` and `State.modify` .
52
+ # @return [A!{e}]
53
+ # returns `A` , without modification by value handler.
54
+ # But it still has the possibility to invoke effects(`e`).
55
+ def with_init(init, &th)
56
+ # not a parameter passing style, or so-called *pure* implementation,
57
+ # just using mutable assignment
23
58
  state = init
24
59
 
25
60
  Ruff.handler
26
- .on(@modify) do |k, fn|
61
+ .on(@eff.modify) do |k, fn|
27
62
  state = fn[state]
28
63
  k[nil]
29
- end
30
- .on(@get) do |k|
64
+ end.on(@eff.get) do |k|
31
65
  k[state]
32
66
  end
33
- .run &task
67
+ .run(&th)
34
68
  end
35
69
 
36
- def with(&task)
37
- with_init(nil, &task)
70
+ # is a short hand for `with_init(nil, th)` .
71
+ #
72
+ # @param [Proc<(), A!{State.get, State.modify,, e}>] th
73
+ # is a thunk returning `A` with the possibility to invoke effects,
74
+ # including `State.get` and `State.modify` .
75
+ # @return [A!{e}]
76
+ # returns `A` , without modification by value handler.
77
+ # But it still has the possibility to invoke effects(`e`).
78
+ def with(&th)
79
+ with_init(nil, &th)
38
80
  end
81
+
82
+ # You can reimplement the handler using these effect instances
83
+ # with accessing `#eff.get` and `#eff.modify` .
84
+ attr_reader :eff
39
85
  end
40
86
 
41
87
  # ---
42
88
  @inst = Instance.new
89
+ @eff = @inst.eff
43
90
 
91
+ # @see Ruff::Standard::State::Instance#get
44
92
  def get
45
93
  @inst.get
46
94
  end
47
95
 
96
+ # @see Ruff::Standard::State::Instance#modify
48
97
  def modify(&fn)
49
- @inst.modify &fn
98
+ @inst.modify(&fn)
50
99
  end
51
100
 
101
+ # @see Ruff::Standard::State::Instance#put
52
102
  def put(s)
53
103
  @inst.put s
54
104
  end
55
105
 
106
+ # @see Ruff::Standard::State::Instance#with_init
56
107
  def with_init(init, &task)
57
108
  @inst.with_init init, &task
58
109
  end
59
110
 
111
+ # @see Ruff::Standard::State::Instance#with
60
112
  def with(&task)
61
- @inst.with &task
113
+ @inst.with(&task)
62
114
  end
63
115
 
64
116
  module_function :get, :put, :modify, :with, :with_init
117
+
118
+ # @see Ruff::Standard::Instance#eff
119
+ attr_reader :eff
65
120
  end