algebrick 0.7.3 → 0.7.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/lib/algebrick/matchers/abstract.rb +3 -3
- data/lib/algebrick/product_constructors/abstract.rb +6 -0
- data/lib/algebrick/reclude.rb +9 -4
- metadata +40 -39
- data/doc/actor.rb +0 -21
- data/doc/data.in.rb +0 -99
- data/doc/extending_behavior.in.rb +0 -61
- data/doc/format.rb +0 -76
- data/doc/init.rb +0 -1
- data/doc/json.in.rb +0 -39
- data/doc/null.in.rb +0 -36
- data/doc/parametrized.in.rb +0 -37
- data/doc/pattern_matching.in.rb +0 -144
- data/doc/quick_example.in.rb +0 -27
- data/doc/tree1.in.rb +0 -10
- data/doc/type_def.in.rb +0 -21
- data/doc/values.in.rb +0 -52
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 031ca75f438646afcde4c41e4ab4e3b5db005f2e
|
4
|
+
data.tar.gz: 877ecd44cd33213e95f0a9bff41eb13f9300b45b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1401bf9922ffd3a3cf6c66b215c249e8b0adb910c7f5325debe0158aef55b4d75c1b0020b26fa563372e5e5cd96b2e97be93418b72358138014215f5643a0440
|
7
|
+
data.tar.gz: c034a72430b4ba328b180068c70a0fe5a661f01a80ca8cfcb09808b8df821b013847a15aadd166c3576abfe411e07b84ddbd5131863d8f274d34773a7ad7bf91
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.7.
|
1
|
+
0.7.4
|
data/lib/algebrick/reclude.rb
CHANGED
@@ -17,14 +17,19 @@ module Algebrick
|
|
17
17
|
#noinspection RubySuperCallWithoutSuperclassInspection
|
18
18
|
module Reclude
|
19
19
|
def included(base)
|
20
|
-
|
20
|
+
used_by << base
|
21
|
+
super(base)
|
22
|
+
end
|
23
|
+
|
24
|
+
def extended(base)
|
25
|
+
used_by << base
|
21
26
|
super(base)
|
22
27
|
end
|
23
28
|
|
24
29
|
def include(*modules)
|
25
30
|
super(*modules)
|
26
31
|
modules.reverse.each do |module_being_included|
|
27
|
-
|
32
|
+
used_by.each do |mod|
|
28
33
|
mod.send :include, module_being_included
|
29
34
|
end
|
30
35
|
end
|
@@ -32,8 +37,8 @@ module Algebrick
|
|
32
37
|
|
33
38
|
private
|
34
39
|
|
35
|
-
def
|
36
|
-
@
|
40
|
+
def used_by
|
41
|
+
@used_by ||= []
|
37
42
|
end
|
38
43
|
end
|
39
44
|
end
|
metadata
CHANGED
@@ -1,43 +1,71 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: algebrick
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.7.
|
4
|
+
version: 0.7.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Petr Chalupa
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-01-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: minitest
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '5.10'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
26
|
+
version: '5.10'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: minitest-reporters
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
33
|
+
version: '1.1'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - "
|
38
|
+
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
40
|
+
version: '1.1'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: yard
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0.9'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0.9'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: kramdown
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.13'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.13'
|
41
69
|
description: Provides algebraic type definitions and pattern matching
|
42
70
|
email: git+algebrick@pitr.ch
|
43
71
|
executables: []
|
@@ -47,56 +75,30 @@ extra_rdoc_files:
|
|
47
75
|
- README.md
|
48
76
|
- README_FULL.md
|
49
77
|
- VERSION
|
50
|
-
- doc/actor.rb
|
51
|
-
- doc/data.in.rb
|
52
78
|
- doc/data.out.rb
|
53
|
-
- doc/extending_behavior.in.rb
|
54
79
|
- doc/extending_behavior.out.rb
|
55
|
-
- doc/format.rb
|
56
|
-
- doc/init.rb
|
57
|
-
- doc/json.in.rb
|
58
80
|
- doc/json.out.rb
|
59
|
-
- doc/null.in.rb
|
60
81
|
- doc/null.out.rb
|
61
|
-
- doc/parametrized.in.rb
|
62
82
|
- doc/parametrized.out.rb
|
63
|
-
- doc/pattern_matching.in.rb
|
64
83
|
- doc/pattern_matching.out.rb
|
65
|
-
- doc/quick_example.in.rb
|
66
84
|
- doc/quick_example.out.rb
|
67
|
-
- doc/tree1.in.rb
|
68
85
|
- doc/tree1.out.rb
|
69
|
-
- doc/type_def.in.rb
|
70
86
|
- doc/type_def.out.rb
|
71
|
-
- doc/values.in.rb
|
72
87
|
- doc/values.out.rb
|
73
88
|
files:
|
74
89
|
- LICENSE.txt
|
75
90
|
- README.md
|
76
91
|
- README_FULL.md
|
77
92
|
- VERSION
|
78
|
-
- doc/actor.rb
|
79
|
-
- doc/data.in.rb
|
80
93
|
- doc/data.out.rb
|
81
|
-
- doc/extending_behavior.in.rb
|
82
94
|
- doc/extending_behavior.out.rb
|
83
|
-
- doc/format.rb
|
84
|
-
- doc/init.rb
|
85
|
-
- doc/json.in.rb
|
86
95
|
- doc/json.out.rb
|
87
|
-
- doc/null.in.rb
|
88
96
|
- doc/null.out.rb
|
89
|
-
- doc/parametrized.in.rb
|
90
97
|
- doc/parametrized.out.rb
|
91
|
-
- doc/pattern_matching.in.rb
|
92
98
|
- doc/pattern_matching.out.rb
|
93
|
-
- doc/quick_example.in.rb
|
94
99
|
- doc/quick_example.out.rb
|
95
|
-
- doc/tree1.in.rb
|
96
100
|
- doc/tree1.out.rb
|
97
|
-
- doc/type_def.in.rb
|
98
101
|
- doc/type_def.out.rb
|
99
|
-
- doc/values.in.rb
|
100
102
|
- doc/values.out.rb
|
101
103
|
- lib/algebrick.rb
|
102
104
|
- lib/algebrick/atom.rb
|
@@ -132,7 +134,7 @@ files:
|
|
132
134
|
- lib/algebrick/value.rb
|
133
135
|
homepage: https://github.com/pitr-ch/algebrick
|
134
136
|
licenses:
|
135
|
-
- Apache
|
137
|
+
- Apache-2.0
|
136
138
|
metadata: {}
|
137
139
|
post_install_message:
|
138
140
|
rdoc_options: []
|
@@ -150,9 +152,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
150
152
|
version: '0'
|
151
153
|
requirements: []
|
152
154
|
rubyforge_project:
|
153
|
-
rubygems_version: 2.
|
155
|
+
rubygems_version: 2.5.1
|
154
156
|
signing_key:
|
155
157
|
specification_version: 4
|
156
158
|
summary: Algebraic types and pattern matching for Ruby
|
157
159
|
test_files: []
|
158
|
-
has_rdoc:
|
data/doc/actor.rb
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
Work = Algebrick.type do
|
2
|
-
fields key: String, work: Proc
|
3
|
-
end
|
4
|
-
|
5
|
-
Finished = Algebrick.type do
|
6
|
-
fields key: String, result: Object, worker: Worker
|
7
|
-
end
|
8
|
-
|
9
|
-
class Worker < AbstractActor
|
10
|
-
def initialize(executor)
|
11
|
-
super()
|
12
|
-
@executor = executor
|
13
|
-
end
|
14
|
-
|
15
|
-
def on_message(message)
|
16
|
-
match message,
|
17
|
-
Work.(~any, ~any) >-> key, work do
|
18
|
-
@executor.tell Finished[key, work.call, self]
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
data/doc/data.in.rb
DELETED
@@ -1,99 +0,0 @@
|
|
1
|
-
extend Algebrick::Matching
|
2
|
-
|
3
|
-
# Simple data structures like trees
|
4
|
-
Tree = Algebrick.type do |tree|
|
5
|
-
variants Tip = type,
|
6
|
-
Node = type { fields value: Object, left: tree, right: tree }
|
7
|
-
end
|
8
|
-
|
9
|
-
module Tree
|
10
|
-
def depth
|
11
|
-
match self,
|
12
|
-
Tip.to_m >> 0,
|
13
|
-
Node.(any, ~any, ~any) >-> left, right do
|
14
|
-
1 + [left.depth, right.depth].max
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end #
|
18
|
-
|
19
|
-
tree = Node[2,
|
20
|
-
Tip,
|
21
|
-
Node[5,
|
22
|
-
Node[4, Tip, Tip],
|
23
|
-
Node[6, Tip, Tip]]]
|
24
|
-
tree.depth
|
25
|
-
|
26
|
-
# Whenever you find yourself to pass around too many fragile Hash-Array structures
|
27
|
-
# e.g. for menus.
|
28
|
-
Menu = Algebrick.type do |menu|
|
29
|
-
Item = Algebrick.type do
|
30
|
-
variants Delimiter = atom,
|
31
|
-
Link = type { fields! label: String, url: String },
|
32
|
-
Group = type { fields! label: String, submenu: menu }
|
33
|
-
end
|
34
|
-
|
35
|
-
fields! item: Item, next: menu
|
36
|
-
variants None = atom, menu
|
37
|
-
end
|
38
|
-
None
|
39
|
-
Item
|
40
|
-
|
41
|
-
module Link
|
42
|
-
def self.new(*fields)
|
43
|
-
super(*fields).tap { |menu| valid! menu.url }
|
44
|
-
end
|
45
|
-
|
46
|
-
def self.valid!(url)
|
47
|
-
# stub
|
48
|
-
end
|
49
|
-
end #
|
50
|
-
|
51
|
-
module Item
|
52
|
-
def draw_menu(indent = 0)
|
53
|
-
match self,
|
54
|
-
Delimiter >-> { [' '*indent + '-'*10] },
|
55
|
-
Link.(label: ~any) >-> label { [' '*indent + label] },
|
56
|
-
(on ~Group do |(label, sub_menu)|
|
57
|
-
[' '*indent + label] + sub_menu.draw_menu(indent + 2)
|
58
|
-
end)
|
59
|
-
end
|
60
|
-
end #
|
61
|
-
|
62
|
-
module Menu
|
63
|
-
def self.build(*items)
|
64
|
-
items.reverse_each.reduce(None) { |menu, item| Menu[item, menu] }
|
65
|
-
end
|
66
|
-
|
67
|
-
include Enumerable
|
68
|
-
|
69
|
-
def each(&block)
|
70
|
-
it = self
|
71
|
-
loop do
|
72
|
-
break if None === it
|
73
|
-
block.call it.item
|
74
|
-
it = it.next
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
def draw_menu(indent = 0)
|
79
|
-
map { |item| item.draw_menu indent }.reduce(&:+)
|
80
|
-
end
|
81
|
-
end #
|
82
|
-
|
83
|
-
sub_menu = Menu.build Link['Red Hat', '#red-hat'],
|
84
|
-
Delimiter,
|
85
|
-
Link['Ubuntu', '#ubuntu'],
|
86
|
-
Link['Mint', '#mint']
|
87
|
-
|
88
|
-
menu = Menu.build Link['Home', '#home'],
|
89
|
-
Delimiter,
|
90
|
-
Group['Linux', sub_menu],
|
91
|
-
Link['About', '#about']
|
92
|
-
|
93
|
-
menu.draw_menu.join("\n")
|
94
|
-
|
95
|
-
|
96
|
-
# Group['Products',
|
97
|
-
# Menu[]],
|
98
|
-
# Link['About', '#about']
|
99
|
-
#]]
|
@@ -1,61 +0,0 @@
|
|
1
|
-
Maybe = Algebrick.type do
|
2
|
-
variants None = atom,
|
3
|
-
Some = type { fields Object }
|
4
|
-
end
|
5
|
-
|
6
|
-
# Types can be extended with usual syntax for modules and using Ruby supports module reopening.
|
7
|
-
module Maybe
|
8
|
-
def maybe(&block)
|
9
|
-
case self
|
10
|
-
when None
|
11
|
-
when Some
|
12
|
-
block.call value
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end #
|
16
|
-
|
17
|
-
# #maybe method is defined on both values (None, Some) of Maybe.
|
18
|
-
None.maybe { |_| raise 'never ever happens' }
|
19
|
-
# Block is called with the value.
|
20
|
-
Some[1].maybe { |v| v*2 }
|
21
|
-
|
22
|
-
# It also works as expected when modules like Comparable are included.
|
23
|
-
Season = Algebrick.type do
|
24
|
-
variants Spring = atom,
|
25
|
-
Summer = atom,
|
26
|
-
Autumn = atom,
|
27
|
-
Winter = atom
|
28
|
-
end
|
29
|
-
|
30
|
-
module Season
|
31
|
-
include Comparable
|
32
|
-
ORDER = Season.variants.each_with_index.each_with_object({}) { |(season, i), h| h[season] = i }
|
33
|
-
|
34
|
-
def <=>(other)
|
35
|
-
Type! other, Season
|
36
|
-
ORDER[self] <=> ORDER[other]
|
37
|
-
end
|
38
|
-
end #
|
39
|
-
|
40
|
-
Quarter = Algebrick.type do
|
41
|
-
fields! year: Integer, season: Season
|
42
|
-
end
|
43
|
-
|
44
|
-
module Quarter
|
45
|
-
include Comparable
|
46
|
-
|
47
|
-
def <=>(other)
|
48
|
-
Type! other, Quarter
|
49
|
-
[year, season] <=> [other.year, other.season]
|
50
|
-
end
|
51
|
-
end #
|
52
|
-
|
53
|
-
# Now Quarters and Seasons can be compared as expected.
|
54
|
-
[Winter, Summer, Spring, Autumn].sort
|
55
|
-
Quarter[2013, Spring] < Quarter[2013, Summer]
|
56
|
-
Quarter[2014, Spring] > Quarter[2013, Summer]
|
57
|
-
Quarter[2014, Spring] == Quarter[2014, Spring]
|
58
|
-
[Quarter[2013, Spring], Quarter[2013, Summer], Quarter[2014, Spring]].sort
|
59
|
-
|
60
|
-
|
61
|
-
|
data/doc/format.rb
DELETED
@@ -1,76 +0,0 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
require 'bundler/setup'
|
3
|
-
require 'pry'
|
4
|
-
require 'pp'
|
5
|
-
|
6
|
-
root = File.dirname(File.expand_path(Process.argv0))
|
7
|
-
input_paths = if ARGV.empty?
|
8
|
-
Dir.glob("#{root}/*.in.rb")
|
9
|
-
else
|
10
|
-
ARGV
|
11
|
-
end.map { |p| File.expand_path p }
|
12
|
-
|
13
|
-
input_paths.each_with_index do |input_path, i|
|
14
|
-
|
15
|
-
pid = fork do
|
16
|
-
require File.join(root, 'init.rb')
|
17
|
-
|
18
|
-
begin
|
19
|
-
output_path = input_path.gsub /\.in\.rb$/, '.out.rb'
|
20
|
-
input = File.readlines(input_path)
|
21
|
-
|
22
|
-
chunks = []
|
23
|
-
line = ''
|
24
|
-
|
25
|
-
while !input.empty?
|
26
|
-
line += input.shift
|
27
|
-
if Pry::Code.complete_expression? line
|
28
|
-
chunks << line
|
29
|
-
line = ''
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
raise unless line.empty?
|
34
|
-
|
35
|
-
chunks.map! { |chunk| [chunk, [chunk.split($/).size, 1].max] }
|
36
|
-
environment = Module.new.send :binding
|
37
|
-
evaluate = ->(code, line) do
|
38
|
-
eval(code, environment, input_path, line)
|
39
|
-
end
|
40
|
-
|
41
|
-
indent = 50
|
42
|
-
|
43
|
-
line_count = 1
|
44
|
-
output = ''
|
45
|
-
chunks.each do |chunk, lines|
|
46
|
-
result = evaluate.(chunk, line_count)
|
47
|
-
unless chunk.strip.empty? || chunk =~ /\A *#/
|
48
|
-
pre_lines = chunk.lines.to_a
|
49
|
-
last_line = pre_lines.pop
|
50
|
-
output << pre_lines.join
|
51
|
-
|
52
|
-
if last_line =~ /\#$/
|
53
|
-
output << last_line.gsub(/\#$/, '')
|
54
|
-
else
|
55
|
-
if last_line.size < indent && result.inspect.size < indent
|
56
|
-
output << "%-#{indent}s %s" % [last_line.chomp, "# => #{result.inspect}\n"]
|
57
|
-
else
|
58
|
-
output << last_line << " # => #{result.inspect}\n"
|
59
|
-
end
|
60
|
-
end
|
61
|
-
else
|
62
|
-
output << chunk
|
63
|
-
end
|
64
|
-
line_count += lines
|
65
|
-
end
|
66
|
-
|
67
|
-
puts "#{input_path}\n -> #{output_path}"
|
68
|
-
#puts output
|
69
|
-
File.write(output_path, output)
|
70
|
-
rescue => ex
|
71
|
-
puts "#{ex} (#{ex.class})\n#{ex.backtrace * "\n"}"
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
Process.wait pid
|
76
|
-
end
|
data/doc/init.rb
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
require 'algebrick'
|
data/doc/json.in.rb
DELETED
@@ -1,39 +0,0 @@
|
|
1
|
-
extend Algebrick::Matching
|
2
|
-
|
3
|
-
# Lets define message-protocol for a cross-process communication.
|
4
|
-
Request = Algebrick.type do
|
5
|
-
User = type { fields login: String, password: String }
|
6
|
-
|
7
|
-
variants CreateUser = type { fields User },
|
8
|
-
GetUser = type { fields login: String }
|
9
|
-
end
|
10
|
-
|
11
|
-
Response = Algebrick.type do
|
12
|
-
variants Success = type { fields Object },
|
13
|
-
Failure = type { fields error: String }
|
14
|
-
end
|
15
|
-
|
16
|
-
Message = Algebrick.type { variants Request, Response }
|
17
|
-
|
18
|
-
require 'algebrick/serializer'
|
19
|
-
require 'multi_json'
|
20
|
-
|
21
|
-
# Prepare a message for sending.
|
22
|
-
serializer = Algebrick::Serializer.new
|
23
|
-
request = CreateUser[User['root', 'lajDh4']]
|
24
|
-
raw_request = MultiJson.dump serializer.dump(request)
|
25
|
-
|
26
|
-
# Receive the message.
|
27
|
-
response = match serializer.load(MultiJson.load(raw_request)),
|
28
|
-
(on CreateUser.(~any) do |user|
|
29
|
-
# create the user and send success
|
30
|
-
Success[user]
|
31
|
-
end)
|
32
|
-
|
33
|
-
# Send response.
|
34
|
-
response_raw = MultiJson.dump serializer.dump(response)
|
35
|
-
|
36
|
-
# Receive response.
|
37
|
-
serializer.load(MultiJson.load(response_raw))
|
38
|
-
|
39
|
-
|
data/doc/null.in.rb
DELETED
@@ -1,36 +0,0 @@
|
|
1
|
-
extend Algebrick::Matching
|
2
|
-
|
3
|
-
def deliver_email(email)
|
4
|
-
true
|
5
|
-
end #
|
6
|
-
|
7
|
-
Contact = Algebrick.type do |contact|
|
8
|
-
variants Null = atom,
|
9
|
-
contact
|
10
|
-
fields username: String, email: String
|
11
|
-
end
|
12
|
-
|
13
|
-
module Contact
|
14
|
-
def username
|
15
|
-
match self,
|
16
|
-
Null >> 'no name',
|
17
|
-
Contact >-> { self[:username] }
|
18
|
-
end
|
19
|
-
def email
|
20
|
-
match self,
|
21
|
-
Null >> 'no email',
|
22
|
-
Contact >-> { self[:email] }
|
23
|
-
end
|
24
|
-
def deliver_personalized_email
|
25
|
-
match self,
|
26
|
-
Null >> true,
|
27
|
-
Contact >-> { deliver_email(self.email) }
|
28
|
-
end
|
29
|
-
end #
|
30
|
-
|
31
|
-
peter = Contact['peter', 'example@dot.com']
|
32
|
-
john = Contact[username: 'peter', email: 'example@dot.com']
|
33
|
-
nobody = Null
|
34
|
-
|
35
|
-
[peter, john, nobody].map &:email
|
36
|
-
[peter, john, nobody].map &:deliver_personalized_email
|
data/doc/parametrized.in.rb
DELETED
@@ -1,37 +0,0 @@
|
|
1
|
-
# Let's define Tree but this time parameterized by :value_type,
|
2
|
-
Tree = Algebrick.type(:value_type) do |tree|
|
3
|
-
variants Empty = atom,
|
4
|
-
Leaf = type(:value_type) { fields value: :value_type },
|
5
|
-
Node = type(:value_type) { fields left: tree, right: tree }
|
6
|
-
end
|
7
|
-
|
8
|
-
# with method depth defined as before.
|
9
|
-
module Tree
|
10
|
-
def depth
|
11
|
-
match self,
|
12
|
-
Empty >> 0,
|
13
|
-
Leaf >> 1,
|
14
|
-
Node.(~any, ~any) >-> left, right do
|
15
|
-
1 + [left.depth, right.depth].max
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end #
|
19
|
-
|
20
|
-
# Then Tree, Leaf, Node are
|
21
|
-
Tree.class
|
22
|
-
[Tree, Leaf, Node]
|
23
|
-
# which servers as factories to actual types.
|
24
|
-
Tree[Float]
|
25
|
-
Tree[String]
|
26
|
-
|
27
|
-
# Types cannot be mixed.
|
28
|
-
Leaf[Integer]['1'] rescue $!
|
29
|
-
Node[Integer][Leaf[String]['a'], Empty] rescue $!
|
30
|
-
Leaf[String]['1']
|
31
|
-
|
32
|
-
# Depth method works as before.
|
33
|
-
integer_tree = Node[Integer][Leaf[Integer][2], Empty]
|
34
|
-
integer_tree.depth
|
35
|
-
string_tree = Node[String][Empty, Empty]
|
36
|
-
string_tree.depth
|
37
|
-
|
data/doc/pattern_matching.in.rb
DELETED
@@ -1,144 +0,0 @@
|
|
1
|
-
# Let's define a tree and binary tree to demonstrate the pattern matching abilities.
|
2
|
-
Tree = Algebrick.type do |tree|
|
3
|
-
variants Empty = type,
|
4
|
-
Leaf = type { fields Integer },
|
5
|
-
Node = type { fields tree, tree }
|
6
|
-
end
|
7
|
-
|
8
|
-
BinaryTree = BTree = Algebrick.type do |btree|
|
9
|
-
fields! value: Comparable, left: btree, right: btree
|
10
|
-
variants Empty, btree
|
11
|
-
end
|
12
|
-
|
13
|
-
extend Algebrick::Matching
|
14
|
-
|
15
|
-
# Product matchers are constructed with #.() syntax.
|
16
|
-
Leaf.(any) === Leaf[1]
|
17
|
-
Leaf.(1) === Leaf[1]
|
18
|
-
Leaf.(2) === Leaf[1]
|
19
|
-
# There are also some shortcuts to use when product has more fields.
|
20
|
-
BTree.()
|
21
|
-
BTree.(value: any, left: Empty)
|
22
|
-
BTree.(value: any, left: Empty) === BTree[1, Empty, Empty]
|
23
|
-
|
24
|
-
# Any object responding to #=== can be converted to matcher.
|
25
|
-
(1..2).to_m
|
26
|
-
(1..2).to_m === 2
|
27
|
-
Empty.to_m
|
28
|
-
# As matchers are using standard #=== method it does not have to be always converted.
|
29
|
-
Empty === Empty
|
30
|
-
Leaf === Leaf[1]
|
31
|
-
|
32
|
-
# Tree matches all its values.
|
33
|
-
[Empty, Leaf[1], Node[Empty, Empty]].all? { |v| Tree === v }
|
34
|
-
|
35
|
-
# There is also a #match method in Matching module to make pattern matching easier.
|
36
|
-
match Leaf[1], # supply the value for matching
|
37
|
-
# if Leaf.(0) matches :zero is returned
|
38
|
-
(on Leaf.(0), :zero),
|
39
|
-
# when computation of the result needs to be avoided use block
|
40
|
-
# if Leaf.(1) matches block is called and its result is returned
|
41
|
-
(on Leaf.(1) do
|
42
|
-
(1..10000).inject(:*) # expensive computation
|
43
|
-
:one # which is :one in this case
|
44
|
-
end)
|
45
|
-
|
46
|
-
# Alternatively case can be used.
|
47
|
-
case Leaf[1]
|
48
|
-
when Leaf.(0)
|
49
|
-
:zero
|
50
|
-
when Leaf.(1)
|
51
|
-
(1..10000).inject(:*) # expensive computation
|
52
|
-
:one
|
53
|
-
end
|
54
|
-
|
55
|
-
# But that won't work nicely with value deconstruction.
|
56
|
-
# Each matcher can be marked with #~ method to store value against which is being matched,
|
57
|
-
# each matched value is passed to the block, ...
|
58
|
-
match Leaf[0],
|
59
|
-
(on ~Leaf.(~any) do |leaf, value|
|
60
|
-
[leaf, value]
|
61
|
-
end)
|
62
|
-
|
63
|
-
btree = BTree[1,
|
64
|
-
BTree[0, Empty, Empty],
|
65
|
-
Empty]
|
66
|
-
match btree,
|
67
|
-
(on BTree.(any, ~any, ~any) do |left, right|
|
68
|
-
[left, right]
|
69
|
-
end)
|
70
|
-
|
71
|
-
# or alternatively you can use Ruby's multi-assignment feature.
|
72
|
-
match btree,
|
73
|
-
(on ~BTree do |(_, left, right)|
|
74
|
-
[left, right]
|
75
|
-
end)
|
76
|
-
|
77
|
-
|
78
|
-
# Matchers also support logical operations #& for and, #| for or, and #! for negation.
|
79
|
-
Color = Algebrick.type do
|
80
|
-
variants Black = atom,
|
81
|
-
White = atom,
|
82
|
-
Pink = atom,
|
83
|
-
Grey = type { fields scale: Float }
|
84
|
-
end
|
85
|
-
|
86
|
-
def color?(color)
|
87
|
-
match color,
|
88
|
-
on(Black | Grey.(-> v { v < 0.2 }), 'black-ish'),
|
89
|
-
on(White | Grey.(-> v { v > 0.8 }), 'white-ish'),
|
90
|
-
on(Grey.(-> v { v >= 0.2 }) & Grey.(-> v { v <= 0.8 }), 'grey-ish'),
|
91
|
-
on(Pink, "that's not a color ;)")
|
92
|
-
end
|
93
|
-
|
94
|
-
color? Black
|
95
|
-
color? Grey[0.1]
|
96
|
-
color? Grey[0.3]
|
97
|
-
color? Grey[0.9]
|
98
|
-
color? White
|
99
|
-
color? Pink
|
100
|
-
|
101
|
-
# A more complicated example of extracting node's value and values of its left and right side
|
102
|
-
# using also logical operators to allow Empty sides.
|
103
|
-
match BTree[0, Empty, BTree[1, Empty, Empty]],
|
104
|
-
(on BTree.({ value: ~any,
|
105
|
-
left: Empty | BTree.(value: ~any),
|
106
|
-
right: Empty | BTree.(value: ~any) }) do |value, left, right|
|
107
|
-
{ left: left, value: value, right: right }
|
108
|
-
end)
|
109
|
-
|
110
|
-
# It also supports matching against Ruby Arrays
|
111
|
-
Array.() === []
|
112
|
-
Array.() === [1]
|
113
|
-
Array.(*any) === []
|
114
|
-
Array.(*any) === [1]
|
115
|
-
Array.(*any) === [1, 2]
|
116
|
-
Array.(1, *any) === []
|
117
|
-
Array.(1, *any) === [1]
|
118
|
-
Array.(1, *any) === [1, 2]
|
119
|
-
|
120
|
-
match [],
|
121
|
-
on(~Array.to_m) { |v| v }
|
122
|
-
match [],
|
123
|
-
on(~Array.()) { |v| v }
|
124
|
-
match [1, 2],
|
125
|
-
on(~Array.(*any)) { |v| v }
|
126
|
-
match [1, 2],
|
127
|
-
on(~Array.(*any)) { |(v, _)| v }
|
128
|
-
match [1, 2, 3],
|
129
|
-
on(Array.(any, *~any)) { |v| v }
|
130
|
-
match [:first, 1, 2, 3],
|
131
|
-
on(Array.(:first, ~any, *any)) { |v| v }
|
132
|
-
match [:+, 1, 2, :foo, :bar],
|
133
|
-
(on Array.(:+, ~Integer.to_m, ~Integer.to_m, *~any) do |int1, int2, rest|
|
134
|
-
{ sum: int1 + int2, rest: rest }
|
135
|
-
end)
|
136
|
-
|
137
|
-
|
138
|
-
# There is also a more funky syntax for matching
|
139
|
-
# using #>, #>> and Ruby 1.9 syntax for lambdas `-> {}`.
|
140
|
-
match Leaf[1],
|
141
|
-
Leaf.(0) >> :zero,
|
142
|
-
Leaf.(~any) >-> value do
|
143
|
-
(1..value).inject(:*) # an expensive computation
|
144
|
-
end
|
data/doc/quick_example.in.rb
DELETED
@@ -1,27 +0,0 @@
|
|
1
|
-
# Let's define a Tree
|
2
|
-
Tree = Algebrick.type do |tree|
|
3
|
-
variants Empty = atom,
|
4
|
-
Leaf = type { fields Integer },
|
5
|
-
Node = type { fields tree, tree }
|
6
|
-
end
|
7
|
-
|
8
|
-
# Now types `Tree(Empty | Leaf | Node)`, `Empty`, `Leaf(Integer)` and `Node(Tree, Tree)` are defined.
|
9
|
-
# Let's add a method, don't miss the **pattern matching** example.
|
10
|
-
module Tree
|
11
|
-
# compute depth of a tree
|
12
|
-
def depth
|
13
|
-
match self,
|
14
|
-
(on Empty, 0),
|
15
|
-
(on Leaf, 1),
|
16
|
-
# ~ will store and pass matched parts to variables left and right
|
17
|
-
(on Node.(~any, ~any) do |left, right|
|
18
|
-
1 + [left.depth, right.depth].max
|
19
|
-
end)
|
20
|
-
end
|
21
|
-
end #
|
22
|
-
|
23
|
-
# Method defined in module `Tree` are passed down to **all** values of type Tree.
|
24
|
-
Empty.depth
|
25
|
-
Leaf[10].depth
|
26
|
-
Node[Leaf[4], Empty].depth
|
27
|
-
Node[Empty, Node[Leaf[1], Empty]].depth
|
data/doc/tree1.in.rb
DELETED
data/doc/type_def.in.rb
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
# Let's define some types
|
2
|
-
Maybe = Algebrick.type do
|
3
|
-
variants None = atom,
|
4
|
-
Some = type { fields Numeric }
|
5
|
-
end
|
6
|
-
|
7
|
-
# where the Maybe actually is:
|
8
|
-
Maybe.class
|
9
|
-
Maybe.class.superclass
|
10
|
-
Maybe.class.superclass.superclass
|
11
|
-
Maybe.class.superclass.superclass.superclass
|
12
|
-
|
13
|
-
# if there is a circular dependency you can define the dependent types inside the block like this:
|
14
|
-
Tree = Algebrick.type do |tree|
|
15
|
-
variants Empty = type,
|
16
|
-
Leaf = type { fields Integer },
|
17
|
-
Node = type { fields tree, tree }
|
18
|
-
end
|
19
|
-
Empty
|
20
|
-
Leaf
|
21
|
-
Node
|
data/doc/values.in.rb
DELETED
@@ -1,52 +0,0 @@
|
|
1
|
-
# Let's define a Tree
|
2
|
-
Tree = Algebrick.type do |tree|
|
3
|
-
variants Empty = type,
|
4
|
-
Leaf = type { fields Integer },
|
5
|
-
Node = type { fields tree, tree }
|
6
|
-
end
|
7
|
-
|
8
|
-
# Values of atomic types are represented by itself,
|
9
|
-
# they are theirs own value.
|
10
|
-
Empty.kind_of? Algebrick::Value
|
11
|
-
Empty.kind_of? Algebrick::Type
|
12
|
-
Empty.kind_of? Empty
|
13
|
-
|
14
|
-
# Values of product types are constructed with #[] and they are immutable.
|
15
|
-
Leaf[1].kind_of? Algebrick::Value
|
16
|
-
Leaf[1].kind_of? Leaf
|
17
|
-
Node[Empty, Empty].kind_of? Node
|
18
|
-
|
19
|
-
# Variant does not have its own values, it uses atoms and products.
|
20
|
-
Leaf[1].kind_of? Tree
|
21
|
-
Empty.kind_of? Tree
|
22
|
-
|
23
|
-
# Product can have its fields named.
|
24
|
-
BinaryTree = BTree = Algebrick.type do |btree|
|
25
|
-
fields! value: Integer, left: btree, right: btree
|
26
|
-
variants Tip = atom, btree
|
27
|
-
end
|
28
|
-
|
29
|
-
# Then values can be created with names
|
30
|
-
tree1 = BTree[value: 1, left: Tip, right: Tip]
|
31
|
-
# or without them as before.
|
32
|
-
BTree[0, Tip, tree1]
|
33
|
-
|
34
|
-
# Fields of products can be read as follows:
|
35
|
-
# 1. When type has only one field method #value is defined
|
36
|
-
Leaf[1].value
|
37
|
-
# 2. By multi-assign
|
38
|
-
v, left, right = BTree[value: 1, left: Tip, right: Tip]
|
39
|
-
[v, left, right]
|
40
|
-
# 3. With #[] method when fields are named
|
41
|
-
BTree[value: 1, left: Tip, right: Tip][:value]
|
42
|
-
BTree[value: 1, left: Tip, right: Tip][:left]
|
43
|
-
# 4. With methods named by fields when fields are named
|
44
|
-
# (it can be disabled if fields are defined with #fields instead of #fields!)
|
45
|
-
BTree[1, Tip, Tip].value
|
46
|
-
BTree[1, Tip, Tip].left
|
47
|
-
|
48
|
-
# Product instantiation raises TypeError when being constructed with wrong type.
|
49
|
-
Leaf['a'] rescue $!
|
50
|
-
Node[nil, Empty] rescue $!
|
51
|
-
|
52
|
-
|