Rakefile in fear-0.11.0 vs Rakefile in fear-1.0.0
- old
+ new
@@ -1,334 +1,301 @@
require 'bundler/gem_tasks'
require 'benchmark/ips'
require_relative 'lib/fear'
namespace :perf do
- namespace :guard do
- task :and1 do
- condition = Integer
+ # Contains benchmarking against Dry-rb
+ namespace :dry do
+ task :some_fmap_vs_fear_some_map do
+ require 'dry/monads/maybe'
+ dry = Dry::Monads::Some.new(42)
+ fear = Fear.some(42)
+
Benchmark.ips do |x|
- x.report('Guard.new') do |n|
- Fear::PartialFunction::Guard.new(condition) === n
- end
+ x.report('Dry') { dry.fmap(&:itself) }
- x.report('Guard.single') do |n|
- Fear::PartialFunction::Guard.and1(condition) === n
- end
+ x.report('Fear') { fear.map(&:itself) }
x.compare!
end
end
- task :and1 do
- first = Integer
+ task :do_vs_fear_for do
+ require 'dry/monads/maybe'
+ require 'dry/monads/do'
- and1 = Fear::PartialFunction::Guard.and1(first)
- guard = Fear::PartialFunction::Guard.new(first)
+ class Operation
+ include Dry::Monads::Maybe::Mixin
+ include Dry::Monads::Do.for(:call)
- Benchmark.ips do |x|
- x.report('guard') do |n|
- and1 === n
- end
+ def call
+ m1 = Some(1)
+ m2 = Some(2)
- x.report('single') do |n|
- guard === n
- end
+ one = yield m1
+ two = yield m2
- x.compare!
+ Some(one + two)
+ end
end
- end
- task :and2 do
- first = Integer
- second = ->(x) { x > 2 }
+ op = Operation.new
- and2 = Fear::PartialFunction::Guard.and2(first, second)
- and_and = Fear::PartialFunction::Guard.new(first).and(Fear::PartialFunction::Guard.new(second))
-
Benchmark.ips do |x|
- x.report('and2') do |n|
- and2 === n
- end
+ x.report('Dry') { op.call }
- x.report('Guard#and') do |n|
- and_and === n
+ x.report('Fear') do |_n|
+ Fear.for(Fear.some(1), Fear.some(2)) do |one, two|
+ one + two
+ end
end
x.compare!
end
end
+ end
- task :and3 do
- first = Integer
- second = ->(x) { x > 2 }
- third = ->(x) { x < 10 }
+ # Contains internal benchmarking to if optimization works
+ namespace :fear do
+ task :fear_pattern_extracting_with_vs_without_cache do
+ some = Fear.some([:err, 'not found'])
- and3 = Fear::PartialFunction::Guard.and3(first, second, third)
+ class WOCache < Fear::Extractor::Pattern
+ def initialize(pattern)
+ @matcher = compile_pattern_without_cache(pattern)
+ end
+ end
+ pattern = 'Fear::Some([:err, code])'
- and_and_and = Fear::PartialFunction::Guard.new(first)
- .and(Fear::PartialFunction::Guard.new(second))
- .and(Fear::PartialFunction::Guard.new(third))
-
Benchmark.ips do |x|
- x.report('Guard.and3') do |n|
- and3 === n
+ x.report('With cache') do |_n|
+ Fear::Extractor::Pattern.new(pattern).extracted_arguments(some)
end
- x.report('Guard#and') do |n|
- and_and_and === n
+ x.report('Without cache') do |_n|
+ WOCache.new(pattern).extracted_arguments(some)
end
x.compare!
end
end
- end
- require 'qo'
- require 'dry/matcher'
+ namespace :guard do
+ task :and1_vs_new do
+ condition = Integer
- namespace :pattern_matching do
- task :try do
- module ExhaustivePatternMatch
- def initialize(*)
- super
- @default ||= self.else { raise Fear::MatchError }
+ Benchmark.ips do |x|
+ x.report('Guard.new') do |n|
+ Fear::PartialFunction::Guard.new(condition) === n
+ end
+
+ x.report('Guard.and1') do |n|
+ Fear::PartialFunction::Guard.and1(condition) === n
+ end
+
+ x.compare!
end
end
- SuccessBranch = Qo.create_branch(name: 'success', precondition: Fear::Success, extractor: :get)
- FailureBranch = Qo.create_branch(name: 'failure', precondition: Fear::Failure, extractor: :exception)
+ task :and2_vs_and do
+ first = Integer
+ second = ->(x) { x > 2 }
- PatternMatch = Qo.create_pattern_match(
- branches: [
- SuccessBranch,
- FailureBranch,
- ],
- ).prepend(ExhaustivePatternMatch)
+ and2 = Fear::PartialFunction::Guard.and2(first, second)
+ and_and = Fear::PartialFunction::Guard.new(first).and(Fear::PartialFunction::Guard.new(second))
- Fear::Success.include(PatternMatch.mixin(as: :qo_match))
+ Benchmark.ips do |x|
+ x.report('and2') do |n|
+ and2 === n
+ end
- success_case = Dry::Matcher::Case.new(
- match: lambda { |try, *pattern|
- try.is_a?(Fear::Success) && pattern.all? { |p| p === try.get }
- },
- resolve: ->(try) { try.get },
- )
+ x.report('Guard#and') do |n|
+ and_and === n
+ end
- failure_case = Dry::Matcher::Case.new(
- match: lambda { |try, *pattern|
- try.is_a?(Fear::Failure) && pattern.all? { |p| p === try.exception }
- },
- resolve: ->(value) { value.exception },
- )
+ x.compare!
+ end
+ end
- # Build the matcher
- matcher = Dry::Matcher.new(success: success_case, failure: failure_case)
+ task :and3_vs_and_and do
+ first = Integer
+ second = ->(x) { x > 2 }
+ third = ->(x) { x < 10 }
- success = Fear::Success.new(4)
+ and3 = Fear::PartialFunction::Guard.and3(first, second, third)
- Benchmark.ips do |x|
- x.report('Qo') do
- success.qo_match do |m|
- m.failure { |y| y }
- m.success(->(y) { y % 4 == 0 }) { |y| y }
- m.success { 'else' }
- end
- end
+ and_and_and = Fear::PartialFunction::Guard.new(first)
+ .and(Fear::PartialFunction::Guard.new(second))
+ .and(Fear::PartialFunction::Guard.new(third))
- x.report('Fear') do
- success.match do |m|
- m.failure { |y| y }
- m.success(->(y) { y % 4 == 0 }) { |y| y }
- m.success { 'else' }
+ Benchmark.ips do |x|
+ x.report('Guard.and3') do |n|
+ and3 === n
end
- end
- x.report('Dr::Matcher') do
- matcher.call(success) do |m|
- m.failure { |_y| 'failure' }
- m.success(->(y) { y % 4 == 0 }) { |y| "2: #{y}" }
- m.success { 'else' }
+ x.report('Guard#and') do |n|
+ and_and_and === n
end
- end
- x.compare!
+ x.compare!
+ end
end
end
- task :either do
- module ExhaustivePatternMatch
- def initialize(*)
- super
- @default ||= self.else { raise Fear::MatchError }
- end
+ task :pattern_matching_construction_vs_execution do
+ matcher = Fear::PatternMatch.new do |m|
+ m.case(Integer) { |x| x * 2 }
+ m.case(String) { |x| x.to_i(10) * 2 }
end
- RightBranch = Qo.create_branch(name: 'right', precondition: Fear::Right, extractor: :right_value)
- LeftBranch = Qo.create_branch(name: 'left', precondition: Fear::Left, extractor: :left_value)
+ Benchmark.ips do |x|
+ x.report('construction') do
+ Fear::PatternMatch.new do |m|
+ m.case(Integer) { |y| y * 2 }
+ m.case(String) { |y| y.to_i(10) * 2 }
+ end
+ end
- PatternMatch = Qo.create_pattern_match(
- branches: [
- RightBranch,
- LeftBranch,
- ],
- ).prepend(ExhaustivePatternMatch)
+ x.report('execution') do
+ matcher.call(42)
+ end
- Fear::Right.include(PatternMatch.mixin(as: :qo_match))
+ x.compare!
+ end
+ end
+ end
- right = Fear::Right.new(4)
+ namespace :pattern_matching do
+ require 'qo'
+ require 'dry/matcher'
+ task :qo_vs_fear_pattern_extraction do
+ User = Struct.new(:id, :name)
+ user = User.new(42, 'Jane')
+
Benchmark.ips do |x|
x.report('Qo') do
- right.qo_match do |m|
- m.left(->(y) { y % 3 == 0 }) { |y| y }
- m.right(->(y) { y % 4 == 0 }) { |y| y }
- m.else { 'else' }
+ Qo.case(user, destructure: true) do |m|
+ m.when(User) { |id, name| [id, name] }
end
end
x.report('Fear') do
- right.match do |m|
- m.left(->(y) { y % 3 == 0 }) { |y| y }
- m.right(->(y) { y % 4 == 0 }) { |y| y }
- m.else { 'else' }
+ Fear.match(user) do |m|
+ m.xcase('User(id, name)') { |id:, name:| [id, name] }
end
end
x.compare!
end
end
- task :option do
+ task :dry_vs_qo_vs_fear_try do
module ExhaustivePatternMatch
def initialize(*)
super
@default ||= self.else { raise Fear::MatchError }
end
end
- SomeBranch = Qo.create_branch(name: 'some', precondition: Fear::Some, extractor: :get)
- NoneBranch = Qo.create_branch(name: 'none', precondition: Fear::None)
+ SuccessBranch = Qo.create_branch(name: 'success', precondition: Fear::Success, extractor: :get)
+ FailureBranch = Qo.create_branch(name: 'failure', precondition: Fear::Failure, extractor: :exception)
PatternMatch = Qo.create_pattern_match(
- branches: [
- SomeBranch,
- NoneBranch,
- ],
+ branches: [SuccessBranch,
+ FailureBranch],
).prepend(ExhaustivePatternMatch)
- Fear::Some.include(PatternMatch.mixin(as: :qo_match))
+ Fear::Success.include(PatternMatch.mixin(as: :qo_match))
- some = Fear::Some.new(4)
-
- some_case = Dry::Matcher::Case.new(
- match: lambda { |option, *pattern|
- option.is_a?(Fear::Some) && pattern.all? { |p| p === option.get }
+ success_case = Dry::Matcher::Case.new(
+ match: lambda { |try, *pattern|
+ try.is_a?(Fear::Success) && pattern.all? { |p| p === try.get }
},
resolve: ->(try) { try.get },
)
- none_case = Dry::Matcher::Case.new(
- match: lambda { |option, *pattern|
- Fear::None == option && pattern.all? { |p| p === option }
+ failure_case = Dry::Matcher::Case.new(
+ match: lambda { |try, *pattern|
+ try.is_a?(Fear::Failure) && pattern.all? { |p| p === try.exception }
},
- resolve: ->(value) { value },
+ resolve: ->(value) { value.exception },
)
- else_case = Dry::Matcher::Case.new(
- match: ->(*) { true },
- resolve: ->(value) { value },
- )
-
# Build the matcher
- matcher = Dry::Matcher.new(some: some_case, none: none_case, else: else_case)
+ matcher = Dry::Matcher.new(success: success_case, failure: failure_case)
- option_matcher = Fear::Option.matcher do |m|
- m.some(->(y) { y % 3 == 0 }) { |y| y }
- m.some(->(y) { y % 4 == 0 }) { |y| y }
- m.none { 'none' }
- m.else { 'else' }
- end
+ success = Fear::Success.new(4)
Benchmark.ips do |x|
x.report('Qo') do
- some.qo_match do |m|
- m.some(->(y) { y % 3 == 0 }) { |y| y }
- m.some(->(y) { y % 4 == 0 }) { |y| y }
- m.none { 'none' }
- m.else { 'else' }
+ success.qo_match do |m|
+ m.failure(&:itself)
+ m.success(Integer, ->(y) { y % 5 == 0 }, &:itself)
+ m.success { 'else' }
end
end
- x.report('Fear::Some#math') do
- some.match do |m|
- m.some(->(y) { y % 3 == 0 }) { |y| y }
- m.some(->(y) { y % 4 == 0 }) { |y| y }
- m.none { 'none' }
- m.else { 'else' }
+ x.report('Fear') do
+ success.match do |m|
+ m.failure(&:itself)
+ m.success(Integer, ->(y) { y % 5 == 0 }, &:itself)
+ m.success { 'else' }
end
end
- x.report('Fear::Option.mather') do
- option_matcher.call(some)
- end
-
- x.report('Dry::Matcher') do
- matcher.call(some) do |m|
- m.some(->(y) { y % 3 == 0 }) { |y| y }
- m.some(->(y) { y % 4 == 0 }) { |y| y }
- m.none { 'none' }
- m.else { 'else' }
+ x.report('Dr::Matcher') do
+ matcher.call(success) do |m|
+ m.failure(&:itself)
+ m.success(Integer, ->(y) { y % 5 == 0 }, &:itself)
+ m.success { 'else' }
end
end
x.compare!
end
end
- task :option_execution do
+ task :qo_vs_fear_try_execution do
module ExhaustivePatternMatch
def initialize(*)
super
@default ||= self.else { raise Fear::MatchError }
end
end
- SomeBranch = Qo.create_branch(name: 'some', precondition: Fear::Some, extractor: :get)
- NoneBranch = Qo.create_branch(name: 'none', precondition: Fear::None)
+ SuccessBranch = Qo.create_branch(name: 'success', precondition: Fear::Success, extractor: :get)
+ FailureBranch = Qo.create_branch(name: 'failure', precondition: Fear::Failure, extractor: :exception)
- PatternMatch = Qo.create_pattern_match(
- branches: [
- SomeBranch,
- NoneBranch,
- ],
+ QoPatternMatch = Qo.create_pattern_match(
+ branches: [SuccessBranch, FailureBranch],
).prepend(ExhaustivePatternMatch)
- some = Fear::Some.new(4)
+ Fear::Success.include(QoPatternMatch.mixin(as: :qo_match))
- qo_matcher = PatternMatch.new do |m|
- m.some(->(y) { y % 3 == 0 }) { |y| y }
- m.some(->(y) { y % 4 == 0 }) { |y| y }
- m.none { 'none' }
- m.else { 'else' }
+ success = Fear::Success.new(4)
+
+ qo_matcher = QoPatternMatch.new do |m|
+ m.success(1, &:itself)
+ m.success(4, &:itself)
+ m.failure { 'failure' }
end
- fear_matcher = Fear::OptionPatternMatch.new do |m|
- m.some(->(y) { y % 3 == 0 }) { |y| y }
- m.some(->(y) { y % 4 == 0 }) { |y| y }
- m.none { 'none' }
- m.else { 'else' }
+ fear_matcher = Fear::TryPatternMatch.new do |m|
+ m.success(1, &:itself)
+ m.success(4, &:itself)
+ m.failure { 'failure' }
end
Benchmark.ips do |x|
x.report('Qo') do
- qo_matcher.call(some)
+ qo_matcher.call(success)
end
x.report('Fear') do
- fear_matcher.call(some)
+ fear_matcher.call(success)
end
x.compare!
end
end
@@ -341,16 +308,18 @@
n * factorial_proc.call(n - 1)
end
end
factorial_pm = Fear.matcher do |m|
- m.case(->(n) { n <= 1 }) { 1 }
+ m.case(1, &:itself)
+ m.case(0, &:itself)
m.else { |n| n * factorial_pm.call(n - 1) }
end
factorial_qo = Qo.match do |m|
- m.when(->(n) { n <= 1 }) { 1 }
+ m.when(1, &:itself)
+ m.when(0, &:itself)
m.else { |n| n * factorial_qo.call(n - 1) }
end
Benchmark.ips do |x|
x.report('Proc') do
@@ -361,31 +330,9 @@
factorial_pm.call(100)
end
x.report('Qo') do
factorial_qo.call(100)
- end
-
- x.compare!
- end
- end
-
- task :construction_vs_execution do
- matcher = Fear::PatternMatch.new do |m|
- m.case(Integer) { |x| x * 2 }
- m.case(String) { |x| x.to_i(10) * 2 }
- end
-
- Benchmark.ips do |x|
- x.report('construction') do
- Fear::PatternMatch.new do |m|
- m.case(Integer) { |y| y * 2 }
- m.case(String) { |y| y.to_i(10) * 2 }
- end
- end
-
- x.report('execution') do
- matcher.call(42)
end
x.compare!
end
end