algebrick 0.7.3 → 0.7.4
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.
- 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
|
-
|