Комментарии 15
Объяснять про монады в Scala без введения понятия typeclass — это несколько необычно.
Это обобщение будет введено в дальнейшем?
А вообще не легкий это труд объяснять ФП. Мне в свое время очень помог learning Scalaz.
Это обобщение будет введено в дальнейшем?
А вообще не легкий это труд объяснять ФП. Мне в свое время очень помог learning Scalaz.
Спасибо за статью.
Нашёл пример:
то
Нашёл пример:
scala> val fruits = Seq("apple", "banana", "orange")
fruits: Seq[java.lang.String] = List(apple, banana, orange)
scala> fruits.map(_.toUpperCase)
res0: Seq[java.lang.String] = List(APPLE, BANANA, ORANGE)
scala> fruits.flatMap(_.toUpperCase)
res1: Seq[Char] = List(A, P, P, L, E, B, A, N, A, N, A, O, R, A, N, G, E)
то
flatMap
— это (=<<)
из Хаскеля, bind
с аргументами в обратном порядке.(=<<) :: Monad m => (a -> m b) -> m a -> m b
-- Same as >>=, but with the arguments interchanged.
> (map toUpper) =<< ["banana","lemon","orange"]
"BANANALEMONORANGE"
Да, но изначально в scala эти методы так не позиционируются, как не позиционируется таким образом и SelectMany в LINQ.
В scalaz же есть и typeclass Bind и метод >>=:
Сводку (несколько устаревшую и не полную) по typeclass в scalaz можно посмотреть в Scalaz cheatsheet.
В scalaz же есть и typeclass Bind и метод >>=:
List("ab", "cd") >>= {_.toUpperCase.toList}
// List(A, B, C, D)
Сводку (несколько устаревшую и не полную) по typeclass в scalaz можно посмотреть в Scalaz cheatsheet.
Кстати, полагаю вам будет интересно, что в scala есть и аналог do-notation — for-comprehensions:
Правда есть отличие: последнее выражение в for — это map, а не flatMap.
for {
f <- fruits
//f2 = f.drop(1)
c <- f.toUpperCase
//if c != 'A'
} yield c
Правда есть отличие: последнее выражение в for — это map, а не flatMap.
Что это я? Они же есть в статье.
for-comprehensions — это do-notation или всего лишь list-comprehension?
Требуется только наличие map и flatMap (для использования if требуется withFilter, но if можно просто не использовать). Работает для коллекций, Option, Try и многих других классов. При наличии соответствующей реализации typeclass Monad будет работать для любого класса.
Скорее monad-comprehensions, т.е. то же, что и list-comprehensions, но для произвольной монады.
> Что касается функции unit, то она отвечает за создание монады и для каждой монады она отличается. Для примера, функция unit.
Насколько я понимаю, в Scala вместо unit используется apply. Таким образом:
«для монады Option это Some(x)», не совсем верно, скорее Option.apply(x)
«для монады List это List(x)» – List.apply(x)
«для монады Try это Success(x)» – Все-таки Try.apply(x), т.к. x тут это анонимная ф-я «x: => T»
Насколько я понимаю, в Scala вместо unit используется apply. Таким образом:
«для монады Option это Some(x)», не совсем верно, скорее Option.apply(x)
«для монады List это List(x)» – List.apply(x)
«для монады Try это Success(x)» – Все-таки Try.apply(x), т.к. x тут это анонимная ф-я «x: => T»
Все-таки на Option(x) есть дополнительная логика — если x == null, то вернется None.
Но если хотите полностью функционального подхода, то в scalaz есть typeclass `Applicative`:
Но если хотите полностью функционального подхода, то в scalaz есть typeclass `Applicative`:
1.point[Option]
1.point[List]
import scalaz.contrib.std.utilTry._
1.point[Try]
Совершенно необязательно иметь определенную функцию для unit.
Она есть в теории, но на практике она в основном by convention, так же она может иметь разные сигнатуры.
Например: вызов
Она есть в теории, но на практике она в основном by convention, так же она может иметь разные сигнатуры.
apply
— это тоже договоренность, которая просто позволяет применять синтаксис вызова функции.Например: вызов
List(x)
— это вызов функции apply
на объекте List
.В вашем примере используется
хотя, результат этого выражения
map
address.map(add => println("Address : " + add)).getOrElse(println("Error"))
// Address : my.host.com/82.98.86.171:22
хотя, результат этого выражения
Unit
. Логичнее было бы использовать foreach
, или вынести println
за скобки.println(address.map(add => "Address: " + add).getOrElse("Error"))
Что касается функции unit, то она отвечает за создание монады и для каждой монады она отличается. Для примера, функция unit.
для монады Option это Some(x)
для монады List это List(x)
для монады Try это Success(x)
Разве Try является монадой? У нее же нарушается left unit law…
Пример:
import scala.util.Try
def f[T]: T => Try[T] = x => throw new Throwable
val num: Int = 5
Try(num) flatMap f
f(num)
Результаты последних двух выражений отличаются, хотя для монады должны быть равны.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Монады в Scala