Преобразование списка параметров в вариант списка с помощью Scalaz
Вопрос
Я хочу преобразовать общий кодовый код в общий кодовый код.Тип сигнатуры функции
родовое слово Ожидаемое поведение - преобразовать список, содержащий только List[Option[T]]
s, в Option[List[T]]
, содержащий список элементов внутри элементов Some
's.С другой стороны, если во входном списке есть хотя бы один Some
, ожидаемым поведением будет просто возврат Some
.Например:
Пример реализации без скаляза:
родовое словоЯ помню, как где-то видел похожий пример, но с использованием Scalaz для упрощения кода.Как бы это выглядело?
Чуть более лаконичная версия, использующая код Scala2.8 None
, но без Scalaz:
Решение
В Scalaz есть функция, которая превращает генерирующий кодовый код в общий кодовый код. Это генерирующий код. Чтобы получить код List[Option[A]]
в случае, если какой-либо из элементов является Option[List[A]]
и sequence
, если все элементы являются None
, вы можете просто сделать следующее:
Этот метод фактически превращает None
в Some[List[A]]
, учитывая, что существует реализация Some
и F[G[A]
(G[F[A]]
и Traverse[F]
удовлетворяют обоим и предоставляются этим импортом).
Семантика Applicative[G]
такова, что если какой-либо из элементов Option
из List
s является Applicative[Option]
, то код List
также будет Option
. Если вы хотите получить список всех значений None
независимо от того, являются ли другие значения sequence
, вы можете сделать следующее:
Вы можете обобщить это для любого None
, который также формирует Some
(None
может быть одним из них):
Другие советы
По какой-то причине вам не нравится
родовое слово?Вероятно, это самый короткий вариант в Scala без Scalaz.
Хотя код Applicative[Option]
в Scalaz не позволяет напрямую использовать код MA#sequence
, вы также можете получить код Applicative
из кода Monoid
. Это удобно с помощью MA#foldMapDefault
или MA#collapse
.
В этом случае мы используем общий кодовый код. Сначала мы выполняем внутреннюю карту (Monoid[Option[List[Int]]
), чтобы обернуть отдельные общие кодовые коды в общие коды одного элемента.
Абстрагирование от MA#∘∘
к любому контейнеру с экземплярами для Int
, List
и List
:
К сожалению, попытка скомпилировать этот код в настоящее время вызывает либо # 2741 , либо отправляет компилятор в бесконечный цикл.
ОБНОВЛЕНИЕ
Чтобы избежать двойного обхода списка, мне следовало использовать Traverse
:
Этот ответ был основан на исходном запросе о том, что пустой список или список, содержащий только общие кодовые коды, должен возвращать общий кодовый код. Кстати, это лучше всего было бы смоделировать с помощью типа Pointed
- Monoid
гарантирует наличие хотя бы одного элемента.
Если вам нужен только общий код кода, есть много более простых способов, указанных в других ответах. Два прямых пути, которые не были упомянуты:
родовое словоУ меня это сработало.Надеюсь, это правильное решение.
Он возвращает None, если одна из опций в списке - None, в противном случае она возвращает Option of List [A]
родовое словоЗапуск генерирующего кода метки и добавление сгенерировать код кода в стандартную библиотеку , вариант для Ответ Рекса Керра :
родовое слово или, если на карту поставлена производительность (во избежание неявного преобразования Scala 2.13
из Option::unless
в flatten
):