Scala: orElse для компонента возвращаемого значения - PullRequest
2 голосов
/ 16 сентября 2011

Мне было поручено прикрепить контрольный журнал к группе вычислений для восстановления значений после факта (то есть людей со знаниями в области бизнеса, чтобы расшифровать, что пошло не так.) Текущий код выглядит примерно так:

def doSomething = f(x) orElse g(x,y,z) orElse h(p,q,r) orElse default

Каждый из них возвращает опцию.Новый код должен возвращать кортеж (Option, Audit.)

. Я реализовал его как

def doSomething = f(x) match{
  case None => g_prime(x,y,z)
  case x @ Some(_) => (x, SomeAuditObject)
}
//and taking some liberties with the actual signature...
def g_prime(x,y,z) = g(x,y,z) match{

и так далее до «по умолчанию».Каждая функция связывается со следующим, следующим и так далее.Мне это не нравитсяЭто слишком важно.Я что-то упустил.Есть какой-то способ думать об этой проблеме, которого я просто не вижу.Что это, кроме переноса возвращаемых значений в другой Option?

Ответы [ 2 ]

8 голосов
/ 16 сентября 2011

Вы можете использовать монады для составления преобразований, которые оставляют контрольный журнал. Вы можете составить ревизии внутри монады. Посмотрите этот ответ для получения более подробной информации.

Я пытался привести пример для вас. Я не знал, как справиться с последним этапом для понимания, которое является 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 и не ограничите, как вы можете извлечь значение из монады (возможно, запишете вывод журнала, если вы это сделаете), вы можете смело предполагать, что каждое преобразование значения будет записано в журнал. И когда значение будет получено, вы получите запись в своем журнале.

2 голосов
/ 16 сентября 2011

Проверяете ли вы только успешное выполнение f, g и т. Д.?

Если это так, я бы заставил doSomething вернуть Option[(YourData, Audit)] (вместо (Option[YourData], Audit)).Затем вы можете составить функции следующим образом:

def doSomething = (f(x) andThen (t => (t, audit_f(x)))) orElse
                  (g(x, y, z) andThen (t => (t, audit_g(x, y, z)))) orElse
                  ... etc.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...