Rakefile in fear-0.10.0 vs Rakefile in fear-0.11.0
- old
+ new
@@ -1,393 +1,786 @@
require 'bundler/gem_tasks'
+require 'benchmark/ips'
+require_relative 'lib/fear'
+
+namespace :perf do
+ namespace :guard do
+ task :and1 do
+ condition = Integer
+
+ Benchmark.ips do |x|
+ x.report('Guard.new') do |n|
+ Fear::PartialFunction::Guard.new(condition) === n
+ end
+
+ x.report('Guard.single') do |n|
+ Fear::PartialFunction::Guard.and1(condition) === n
+ end
+
+ x.compare!
+ end
+ end
+
+ task :and1 do
+ first = Integer
+
+ and1 = Fear::PartialFunction::Guard.and1(first)
+ guard = Fear::PartialFunction::Guard.new(first)
+
+ Benchmark.ips do |x|
+ x.report('guard') do |n|
+ and1 === n
+ end
+
+ x.report('single') do |n|
+ guard === n
+ end
+
+ x.compare!
+ end
+ end
+
+ task :and2 do
+ first = Integer
+ second = ->(x) { x > 2 }
+
+ 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('Guard#and') do |n|
+ and_and === n
+ end
+
+ x.compare!
+ end
+ end
+
+ task :and3 do
+ first = Integer
+ second = ->(x) { x > 2 }
+ third = ->(x) { x < 10 }
+
+ and3 = Fear::PartialFunction::Guard.and3(first, second, third)
+
+ 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
+ end
+
+ x.report('Guard#and') do |n|
+ and_and_and === n
+ end
+
+ x.compare!
+ end
+ end
+ end
+
+ require 'qo'
+ require 'dry/matcher'
+
+ namespace :pattern_matching do
+ task :try do
+ module ExhaustivePatternMatch
+ def initialize(*)
+ super
+ @default ||= self.else { raise Fear::MatchError }
+ end
+ end
+
+ 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: [
+ SuccessBranch,
+ FailureBranch,
+ ],
+ ).prepend(ExhaustivePatternMatch)
+
+ Fear::Success.include(PatternMatch.mixin(as: :qo_match))
+
+ 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 },
+ )
+
+ 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 },
+ )
+
+ # Build the matcher
+ matcher = Dry::Matcher.new(success: success_case, failure: failure_case)
+
+ success = Fear::Success.new(4)
+
+ 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
+
+ x.report('Fear') do
+ success.match do |m|
+ m.failure { |y| y }
+ m.success(->(y) { y % 4 == 0 }) { |y| y }
+ m.success { 'else' }
+ 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' }
+ end
+ end
+
+ x.compare!
+ end
+ end
+
+ task :either do
+ module ExhaustivePatternMatch
+ def initialize(*)
+ super
+ @default ||= self.else { raise Fear::MatchError }
+ end
+ 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)
+
+ PatternMatch = Qo.create_pattern_match(
+ branches: [
+ RightBranch,
+ LeftBranch,
+ ],
+ ).prepend(ExhaustivePatternMatch)
+
+ Fear::Right.include(PatternMatch.mixin(as: :qo_match))
+
+ right = Fear::Right.new(4)
+
+ 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' }
+ 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' }
+ end
+ end
+
+ x.compare!
+ end
+ end
+
+ task :option 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)
+
+ PatternMatch = Qo.create_pattern_match(
+ branches: [
+ SomeBranch,
+ NoneBranch,
+ ],
+ ).prepend(ExhaustivePatternMatch)
+
+ Fear::Some.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 }
+ },
+ resolve: ->(try) { try.get },
+ )
+
+ none_case = Dry::Matcher::Case.new(
+ match: lambda { |option, *pattern|
+ Fear::None == option && pattern.all? { |p| p === option }
+ },
+ resolve: ->(value) { value },
+ )
+
+ 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)
+
+ 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
+
+ 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' }
+ 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' }
+ 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' }
+ end
+ end
+
+ x.compare!
+ end
+ end
+
+ task :option_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)
+
+ PatternMatch = Qo.create_pattern_match(
+ branches: [
+ SomeBranch,
+ NoneBranch,
+ ],
+ ).prepend(ExhaustivePatternMatch)
+
+ some = Fear::Some.new(4)
+
+ 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' }
+ 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' }
+ end
+
+ Benchmark.ips do |x|
+ x.report('Qo') do
+ qo_matcher.call(some)
+ end
+
+ x.report('Fear') do
+ fear_matcher.call(some)
+ end
+
+ x.compare!
+ end
+ end
+
+ task :factorial do
+ factorial_proc = proc do |n|
+ if n <= 1
+ 1
+ else
+ n * factorial_proc.call(n - 1)
+ end
+ end
+
+ factorial_pm = Fear.matcher do |m|
+ m.case(->(n) { n <= 1 }) { 1 }
+ m.else { |n| n * factorial_pm.call(n - 1) }
+ end
+
+ factorial_qo = Qo.match do |m|
+ m.when(->(n) { n <= 1 }) { 1 }
+ m.else { |n| n * factorial_qo.call(n - 1) }
+ end
+
+ Benchmark.ips do |x|
+ x.report('Proc') do
+ factorial_proc.call(100)
+ end
+
+ x.report('Fear') do
+ 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
+ end
+end