-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmonad.rb
More file actions
108 lines (87 loc) · 1.68 KB
/
Copy pathmonad.rb
File metadata and controls
108 lines (87 loc) · 1.68 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
require 'active_support/concern'
module Interned
extend ActiveSupport::Concern
module ClassMethods
def new(*args)
(@instances ||= {})[[self, *args]] ||= super
end
end
end
class Monad
class << self
forward :unit, :new
end
def method_missing(meth, *args)
bind do |x|
self.class.unit(x.__send__(meth, *args))
end
end
end
class Maybe < Monad
class << self
def unit(x)
Just.new(x)
end
end
end
class Nothing < Maybe
include Interned
def inspect
'Nothing'
end
def bind(&f)
self
end
end
class Just < Maybe
def initialize(value)
@value = value
end
def inspect
"Just[#{@value.inspect}]"
end
def bind(&f)
f[@value]
end
end
class List < Monad
include Enumerable
class << self
def unit(x)
Elements.new([x])
end
def empty
@empty ||= Elements.new([])
end
end
def bind(&f)
Mapped.new(self, &f)
end
class Elements < List
def initialize(els)
@els = els.freeze
end
def inspect
"Elements#{@els.inspect}"
end
def each(&block)
@els.each(&block)
end
end
class Mapped < List
def initialize(list, &func)
@list = list
@func = func
end
def inspect
"Mapped{#{@func.inspect} #{@list.inspect}}"
end
def each
@list.each do |x|
@func[x].each do |y|
yield y
end
end
end
end
end