lib/fear/for_api.rb
# frozen_string_literal: true
module Fear
module ForApi
# Syntactic sugar for composition of multiple monadic operations. It supports two such
# operations - +flat_map+ and +map+. Any class providing them
# is supported by +Fear.or+.
#
# Fear.for(Fear.some(2), Fear.some(3)) do |a, b|
# a * b
# end #=> Fear.some(6)
#
# If one of operands is None, the result is None
#
# Fear.for(Fear.some(2), Fear.none()) { |a, b| a * b } #=> Fear.none()
# Fear.for(Fear.none(), Fear.some(2)) { |a, b| a * b } #=> Fear.none()
#
# Lets look at first example:
#
# Fear.for(Fear.some(2), Fear.some(3)) { |a, b| a * b }
#
# it is translated to:
#
# Fear.some(2).flat_map do |a|
# Fear.some(3).map do |b|
# a * b
# end
# end
#
# It works with arrays as well
#
# Fear.for([1, 2], [2, 3], [3, 4]) { |a, b, c| a * b * c }
# #=> [6, 8, 9, 12, 12, 16, 18, 24]
#
# it is translated to:
#
# [1, 2].flat_map do |a|
# [2, 3].flat_map do |b|
# [3, 4].map do |c|
# a * b * c
# end
# end
# end
#
# If you pass lambda instead of monad, it would be evaluated
# only on demand.
#
# Fear.for(proc { Fear.none() }, proc { raise 'kaboom' } ) do |a, b|
# a * b
# end #=> Fear.none()
#
# It does not fail since `b` is not evaluated.
# You can refer to previously defined monads from within lambdas.
#
# maybe_user = find_user('Paul') #=> <#Option value=<#User ...>>
#
# Fear.for(maybe_user, ->(user) { user.birthday }) do |user, birthday|
# "#{user.name} was born on #{birthday}"
# end #=> Fear.some('Paul was born on 1987-06-17')
#
# @param monads [{#map, #flat_map}]
# @return [{#map, #flat_map}]
#
def for(*monads, &block)
Fear::For.(monads, &block)
end
end
end