I’m having a difficult time trying to compose monads of shape Result(Maybe)
.
There are two methods involved in this scenario:
find_by_id(id) # -> Result(Maybe)
update_by_id(id, update) # -> Result(Maybe)
Each of those methods returns Failure
in case of a database error, and Success(None)
when record does not exist.
I want to compose monads in a way, that will first fetch the entity and then send it to update after merging it with some attributes.
Here’s an example:
def update_name(id, name)
find_by_id(id).bind do |maybe|
maybe.bind do |value|
update_by_id(id, value.merge(name: name))
end
end
end
The problem with this implementation is that when a record can not be found, the function will return None
instead of Success(None)
following the convention.
Trying to fix it:
def update_name(id, name)
find_by_id(id).bind do |maybe|
maybe.bind do |value|
update_by_id(id, value.merge(name: name))
end.or Success(None())
end
end
This code returns Success(None)
even in case of a database error during update. .or
will take over for Failure
as well as for None
.
The only way I found to solve this problem is with a conditional:
def update_name(id, name)
find_by_id(id).bind do |maybe|
if maybe.some?
maybe.bind do |value|
update_by_id(id, value.merge(name: name))
end
else
Success(None())
end
end
end
But this does not seem idiomatic. Is there a better way to express this logic?