Уменьшить / свернуть список моноидов, но редуктор возвращает либо - PullRequest
5 голосов
/ 05 июня 2019

Я пару раз оказывался в ситуации, когда у меня есть редуктор / комбайн fn примерно так:

  def combiner(a: String, b: String): Either[String, String] = {
    (a + b).asRight[String]
  }

Это фиктивная реализация, но fn может потерпеть неудачу, поэтому он возвращает либо. Затем у меня есть список значений, которые я хочу пройти с помощью Reduce / Fold. Лучшее, что я могу придумать (при условии, что тип List является моноидом), это:

  def combine(items: Vector[String]) = {

    items.foldLeft(Monoid[String].empty.asRight[String]) { case (acc, value) =>
      acc.flatMap( accStr => combiner(accStr, value))
    }
  }

Это немного неуклюже, и, как довольно общий шаблон, я подозреваю, что есть лучший способ сделать это, используя кошек.

1 Ответ

7 голосов
/ 05 июня 2019

Возможно, вы захотите взглянуть на foldM . Ваш код будет выглядеть примерно так:

Foldable[Vector].foldM(items, "")(combiner)

Метод foldM имеет подпись

def foldM[G[_], A, B](fa: F[A], z: B)(f: (B, A) ⇒ G[B])(implicit G: Monad[G]): G[B]

поэтому в вашем случае параметры типа (-constructor) будут унифицированы следующим образом:

  • G[X] = Either[String, ?]
  • A = String
  • B = String
  • F[X] = Vector[X]

, чтобы f: (A, B) => G[B] стал f: (String, String) => Either[String, String], что в точности соответствует типу combiner при преобразовании в функцию.

...