Вы можете использовать монады для составления преобразований, которые оставляют контрольный журнал. Вы можете составить ревизии внутри монады. Посмотрите этот ответ для получения более подробной информации.
Я пытался привести пример для вас. Я не знал, как справиться с последним этапом для понимания, которое является map
и не дает контрольного следа. Если вы не разрешаете использовать map
, вы не можете использовать для-понимания, но должны использовать простые вызовы flatMap
.
case class WithAudit[A](value: A, audit: String){
def flatMap[B](f: A => WithAudit[B]): WithAudit[B] = {
val bWithAudit = f(value)
WithAudit(bWithAudit.value, audit + ":" + bWithAudit.audit)
}
def map[B](f: A => B): WithAudit[B] = {
WithAudit(f(value), audit + ":applied unknown function")
}
}
def doSomething(in: Option[Int]): WithAudit[Option[Int]] = WithAudit(
in.map(x => x - 23),
"substract 23"
)
def somethingElse(in: Int): WithAudit[String] = WithAudit(
in.toString,
"convert to String"
)
val processed = for(
v <- WithAudit(Some(42), "input Some(42)");
proc <- doSomething(v);
intVal <- WithAudit(proc.getOrElse(0), "if invalid, insert default 0");
asString <- somethingElse(intVal)
) yield asString
println(processed)
Вывод будет
WithAudit(
19,
input Some(42)
:substract 23
:if invalid, insert default 0
:convert to String
:applied unknown function
)
Безопасность
Использование flatMap
для обработки значения обеспечивает предоставление аудита. Если вы не предоставите map
и не ограничите, как вы можете извлечь значение из монады (возможно, запишете вывод журнала, если вы это сделаете), вы можете смело предполагать, что каждое преобразование значения будет записано в журнал. И когда значение будет получено, вы получите запись в своем журнале.