Rakefile
# frozen_string_literal: true
require "bundler/gem_tasks"
require "benchmark/ips"
require "dry/monads"
require_relative "lib/fear"
include Dry::Monads[:maybe]
namespace :perf do
# Contains benchmarking against Dry-rb
namespace :dry do
task :some_fmap_vs_fear_some_map do
dry = Some(42)
fear = Fear.some(42)
Benchmark.ips do |x|
x.report("Dry") { dry.fmap(&:itself) }
x.report("Fear") { fear.map(&:itself) }
x.compare!
end
end
task :do_vs_fear_for do
require "dry/monads/do"
class Operation
include Dry::Monads::Do.for(:call)
def call
m1 = Some(1)
m2 = Some(2)
one = yield m1
two = yield m2
Some(one + two)
end
end
op = Operation.new
Benchmark.ips do |x|
x.report("Dry") { op.() }
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
# Contains internal benchmarking to if optimization works
namespace :fear do
namespace :guard do
task :and1_vs_new do
iterations = 1_000
Benchmark.ips do |x|
x.report("Guard.new") do |n|
iterations.times do
Fear::PartialFunction::Guard.new(Integer) === n
end
end
x.report("Guard.and1") do |n|
iterations.times do
Fear::PartialFunction::Guard.and1(Integer) === n
end
end
x.compare!
end
end
task :and2_vs_and do
iterations = 1_000
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|
iterations.times { and2 === n }
end
x.report("Guard#and") do |n|
iterations.times { and_and === n }
end
x.compare!
end
end
task :and3_vs_and_and do
iterations = 1_000
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|
iterations.times { and3 === n }
end
x.report("Guard#and") do |n|
iterations.times { and_and_and === n }
end
x.compare!
end
end
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
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.(42)
end
x.compare!
end
end
task :option_match_vs_native_pattern_match do
some = Fear.some(42)
Benchmark.ips do |x|
matcher = Fear::Option.matcher do |m|
m.some(41, &:itself)
m.some(42, &:itself)
m.some(45, &:itself)
end
x.report("case ... in ...") do
case some
in Fear::Some(41 => x)
x
in Fear::Some(42 => x)
x
in Fear::Some(43 => x)
x
end
end
x.report("Option#match") do
some.match do |m|
m.some(41, &:itself)
m.some(42, &:itself)
m.some(45, &:itself)
end
end
x.report("Option#matcher") do
matcher.(some)
end
x.compare!
end
end
end
namespace :pattern_matching do
require "dry/matcher"
task :dry_vs_fear_try do
success_case = Dry::Matcher::Case.new(
match: ->(try, *pattern) {
try.is_a?(Fear::Success) && pattern.all? { |p| p === try.get }
},
resolve: ->(try) { try.get },
)
failure_case = Dry::Matcher::Case.new(
match: ->(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("Fear") do
success.match do |m|
m.failure(&:itself)
m.success(Integer, ->(y) { y % 5 == 0 }, &:itself)
m.success { "else" }
end
end
x.report("Dr::Matcher") do
matcher.(success) do |m|
m.failure(&:itself)
m.success(Integer, ->(y) { y % 5 == 0 }, &:itself)
m.success { "else" }
end
end
x.compare!
end
end
task :factorial do
factorial_proc = proc do |n|
if n <= 1
1
else
n * factorial_proc.(n - 1)
end
end
factorial_pm = Fear.matcher do |m|
m.case(1, &:itself)
m.case(0, &:itself)
m.else { |n| n * factorial_pm.(n - 1) }
end
Benchmark.ips do |x|
x.report("Proc") do
factorial_proc.(100)
end
x.report("Fear") do
factorial_pm.(100)
end
x.compare!
end
end
end
end