Почему у опции нет метода сгиба?
-
26-10-2019 - |
Вопрос
интересно, почему scala.Option
нет метода fold
Как это определено:
fold(ifSome: A => B , ifNone: => B)
эквивалентно
map(ifSome).getOrElse(ifNone)
Нет ли не лучше, чем использовать map
+ getOrElse
?
Решение
Ты можешь сделать:
opt foldLeft (els) ((x, y) => fun(x))
или же
(els /: opt) ((x,y) => fun(x))
(Оба решения оценят els
по цене, что может быть не то, что вы хотите. Благодаря Рекс Керр для указания на это.)
Редактировать:
Но вы действительно хотите Катаморфизм cata
(в основном а fold
который не только обрабатывает Some
ценность, но также отображает None
часть, что вы описали)
opt.cata(fun, els)
определяется как (где value
Значение опции удвалена)
def cata[X](some: A => X, none: => X): X = value match {
case None => none
case Some(a) => some(a)
}
что эквивалентно opt.map(some).getOrElse(none)
.
Хотя я должен отметить, что вы должны использовать CATA только тогда, когда это «более естественный» способ выразить его. Есть много случаев, когда простые map
–getOrElse
достаточно, особенно когда это включает в себя потенциально цепочку map
с (Хотя вы также можете цепорить fun
S с функциональной составой, конечно, это зависит от того, хотите ли вы сосредоточиться на составе функции или преобразовании значений.)
Другие советы
Я лично нахожу такие методы, как cata
Это занимает два закрытия, поскольку аргументы часто переусердствуют. Вы действительно получаете читаемость за map
+ getOrElse
? Подумайте о новичке в вашем коде: что они сделают из
opt cata { x => x + 1, 0 }
Вы действительно думаете, что это яснее, чем
opt map { x => x + 1 } getOrElse 0
На самом деле я бы сказал, что ни один из них не предпочтительнее старого старого
opt match {
case Some(x) => x + 1
case None => 0
}
Как всегда, существует ограничение, когда дополнительная абстракция не дает вам преимуществ и становится контрпродуктивным.
Это было наконец добавлено в Scala 2.10, с подписью fold[B](ifEmpty: => B)(f: A => B): B
.
К сожалению, это имеет общее негативное последствие: B
выведен для вызовов, основанных только на ifEmpty
Аргумент, который на практике часто более узкий. Например (правильная версия уже находится в стандартной библиотеке, это просто для демонстрации)
def toList[A](x: Option[A]) = x.fold(Nil)(_ :: Nil)
Скала сделает вывод B
быть Nil.type
вместо желаемого List[A]
и жаловаться на f
не возвращается Nil.type
. Анкет Вместо этого вам нужен один из
x.fold[List[A]](Nil)(_ :: Nil)
x.fold(Nil: List[A])(_ :: Nil)
Это делает fold
не совсем эквивалентно соответствующим match
.
Как упомянуто Debilski, вы можете использовать Скалаз OptionW.cata
или же fold
. Анкет Как прокомментировал Джейсон, названные параметры делают это красивым:
opt.fold { ifSome = _ + 1, ifNone = 0 }
Теперь, если значение, которое вы хотите в None
случай mzero
для некоторых Monoid[M]
и у вас есть функция f: A => M
для Some
Случай, вы можете сделать это:
opt foldMap f
Так,
opt map (_ + 1) getOrElse 0
становится
opt foldMap (_ + 1)
Лично я считаю Option
должен иметь apply
Метод, который был бы катаморфизмом. Таким образом, вы могли бы просто сделать это:
opt { _ + 1, 0 }
или же
opt { some = _ + 1, none = 0 }
На самом деле, это было бы неплохо иметь для всех алгебраических структур данных.