Комментарии 11
def lift[A, B](f: A => B): F[A] => F[B] = map(_)(f)
И эти люди ругали COBOL...
Это Scala, тут по другому никак, хотите элегантности вам к F#/Haskell/ML, а если типы особо не нужны то Clojure вам подойдет.
COBOL не работает на таком уровне абстракций. lift
— мощный универсальный инструмент, который затруднительно даже представить в слабо-абстрактных языках.
Есть хорошие книги и курсы, с помощью которых можно освоить абстракции, используемые в функциональном программировании. Например, FP in Scala (либо аналогичная книжка на Haskell'e — haskellbook.com). На coursera есть специализация "Functional Programming in Scala".
Ну а собственно lift
из обычной функции делает функцию, работающую с какой-то структурой. Например,
val inc: Int => Int = _ + 1
val linc: List[Int] => List[Int] = Functor[List].lift(inc)
val List(11,12,13) = linc(List(10,11,12))
а универсальность позволяет писать код, который не зависит от конкретной структуры:
def algorithm[F[_]: Functor, A: Numeric](fa: F[A]): F[A] = {
val N = Numeric[A]
val F = Functor[F]
val inc = N.plus(_, N.one)
val finc = F.lift(inc)
finc(fa)
}
такой алгоритм будет работать с любыми структурами данных (для которых есть Functor
) и любыми числовыми типами (для которых есть Numeric
).
Разные цели/задачи — разные языки.
Бизнес-логику вполне можно писать на Scala с помощью подходящего DSL. В том числе, и не столь прямолинейную.
"Премудрости" дают инструменты для хороших библиотек и DSL. На прикладном уровне хорошие библиотеки использовать достаточно легко, и можно в большинстве случаев обходиться поверхностными знаниями, не вникая в детали.
Для некоторых задач отсутствие адекватных по сложности инструментов приводит к тому, что программы получаются не очень хорошими (многословными, с повторами похожего кода, с необходимостью заново тестировать похожую функциональность).
То же самое на Haskell:
lift :: (A -> B) -> F A -> F B
lift f = flip map f
не то, чтобы стало сильно легче...
Видимая сложность функции lift
связана с её универсальностью. При использовании, вообще говоря, всё довольно удобно и не выглядит сложным:
val inc: Int => Int = _ + 1
val oinc: Option[Int] => Option[Int] = Option.lift(inc)
val Option(11) = oinc(10.some)
9 советов по использованию библиотеки Cats в Scala