ruff 1.0.1 → 1.1.0

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