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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: acb97762ca9adaf44bcddd29fd57985f77c0d98c
4
- data.tar.gz: 67a118f7462a29d4d29edeeff5cf1ce4c9a4b259
3
+ metadata.gz: 031ca75f438646afcde4c41e4ab4e3b5db005f2e
4
+ data.tar.gz: 877ecd44cd33213e95f0a9bff41eb13f9300b45b
5
5
  SHA512:
6
- metadata.gz: 84402aff0bf09c611f7853ec255b97bdae86a7d43297a412a5d8f1d3aee8ef9c82303a233465b1e22a17f75f7fc2c693ebb3db9d4c194b54952c37941b59a1dc
7
- data.tar.gz: c4250f16434da8d17ce1ca866c1e549694f3960bc9d81a102ff65d908f4f450e69dbe5379c8708028d013d9c0fc49d19981ad05346eeb1084a44a01da4b1979b
6
+ metadata.gz: 1401bf9922ffd3a3cf6c66b215c249e8b0adb910c7f5325debe0158aef55b4d75c1b0020b26fa563372e5e5cd96b2e97be93418b72358138014215f5643a0440
7
+ data.tar.gz: c034a72430b4ba328b180068c70a0fe5a661f01a80ca8cfcb09808b8df821b013847a15aadd166c3576abfe411e07b84ddbd5131863d8f274d34773a7ad7bf91
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.7.3
1
+ 0.7.4
@@ -70,9 +70,9 @@ module Algebrick
70
70
  end
71
71
 
72
72
  def assigns
73
- collect_assigns.tap do
74
- return yield *assigns if block_given?
75
- end
73
+ assigns = collect_assigns
74
+ return yield *assigns if block_given?
75
+ assigns
76
76
  end
77
77
 
78
78
  def to_a
@@ -39,6 +39,12 @@ module Algebrick
39
39
  @fields == other.fields
40
40
  end
41
41
 
42
+ alias_method :eql?, :==
43
+
44
+ def hash
45
+ [self.class, @fields].hash
46
+ end
47
+
42
48
  def self.type
43
49
  @type || raise
44
50
  end
@@ -17,14 +17,19 @@ module Algebrick
17
17
  #noinspection RubySuperCallWithoutSuperclassInspection
18
18
  module Reclude
19
19
  def included(base)
20
- included_into << base
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
- included_into.each do |mod|
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 included_into
36
- @included_into ||= []
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.3
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: 2015-07-02 00:00:00.000000000 Z
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: '0'
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: '0'
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: '0'
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: '0'
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 License 2.0
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.4.5
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:
@@ -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
@@ -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
-
@@ -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
@@ -1 +0,0 @@
1
- require 'algebrick'
@@ -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
-
@@ -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
@@ -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
-
@@ -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
@@ -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
@@ -1,10 +0,0 @@
1
- Tree = Algebrick.type do |tree|
2
- variants Empty = type,
3
- Leaf = type { fields Integer },
4
- Node = type { fields tree, tree }
5
- end
6
- # Which sets 4 modules representing these types in current module/class
7
- Tree
8
- Empty
9
- Leaf
10
- Node
@@ -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
@@ -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
-