A factory of a monad for a one-to-one object mapping relation.
A factory of a monad for a one-to-one object mapping relation.
To initially create a monad instance, use HasA.Monadic.apply()
together with a source object of the mapping and an instance of
HasA[]
which describes a mapping. For instance, a monad for a
mapping from a Car
to an Engine
defined by a HasA[Car,
Engine]
can be generated as the following.
val hasEngine: HasA[Car, Engine] = ??? val car: Car = ??? val m = HasA.Monadic(car, hasEngine)
A monad can implicitly be converted to an option value of the
target type of the mapping by internally invoking HasA.map()
in the conversion.
val engine: Option[Engine] = m
Since it is a monad, the value can mapped to another value in a
for
comprehension. (Assume that an Engine
has id
field of
type Long
in the next example.)
val id: Option[Long] = for { e <- m } yield (e.id)
Note that the e
in the above example, i.e., the argument of a
function passed to flatMap()
or map()
of the monad, is an
Engine
. You don't need to look inside the option value in
this way. If the resulting option value is None
, i.e.,
HasA.map()
does not return a value for the source of the
mapping, then the body of the function passed to flatMap()
or
map()
never be invoked.
A list of monadic values can also be converted to a list of the target list type.
val cars: Seq[Car] = ??? val ms = cars.map { car => HasA.Monadic(car, hasEngine) } val engines: Seq[Engine] = ms
In this case, cars
are mapped to engines
by HasA.map()
all
at once. You can of course use a for
comprehension for
further operations.
val ids: Seq[Long] = ms.map { m => for { e <- m } yield (e.id) }
If you aim to achieve an efficient object mapping by converting
a list value at once via HasA.map()
--- this is the most
common reason for using the monadc object mapping ---, DO
NOT trigger the implicit conversion inside the loop.
val ids: Seq[Long] = ms.map { m => val id: Option[Long] /* !!! HasA.map() is called here !!! */ = for { e <- m } yield (e.id) id }.flatten
It is not difficult to notice the misuse in this way since the
object must be recieved as an Option[Long]
not a Long
to
trigger the conversion for each element.