map[F[_]]:: [A,B] => (A=>B) => F[A] => F[B]
[A,B]
(A => B)
F[_]
(коллекции List[_]
, потоки данных Stream[_]
, ...)F[A] => F[B]
flatMap[F[_]]:: [A,B] => F[A] => (A=>F[B]) => F[B]
bind[F[_]]:: [A,B] => (A=>F[B]) => F[A] => F[B]
map
сигнатурой пользовательской функцииF[_]
с такой операцией называется монадой)Значение F[A]
может иметь несколько структурных форм, укладывающихся в шаблоны.
Каждую форму можно обработать отдельно.
unapply[F[_]]:: [A,B] => F[A] => (*[A]=>B)* => B
(*[A]=>B)*
- условное обозначение, несколько функций на все случаи, возможные в F[_]
List.unapply::[A,B] => List[A] => /*cons*/((A,List[A])=>B), /*nil*/(=>B) => B
- структура списка полностью разбирается парой функций - для пустого и непустого спискаBoolean.unapply::[B] => Boolean => /*true*/(=>B), /*false*/(=>B) => B
- if - тоже является деконструктором типа Boolean
enum Enum = e1|e2|e3
Enum.unapply:: Enum => /*e1*/(=>B), /*e2*/(=>B), /*e3*/(=>B) => B
A
B
S
F[_]
трансдьюсер:
A => S => (S, F[B])
"Алгебры": лирическое отступление
"Алгебры": IO
IO[T]
- вычисление, возвращающее величину T
(или исключение)io.UnsafeRunSync(iot)
- фактически запустить вычисление"Алгебры": Stream
Stream[T]
- абстрактный поток значений типа T
, который может быть превращён в вычисление io.IO[[]T]
IO[A]
Stream[A]
type IO[A any] Continuation[A] type Continuation[A any] func() ResultOrContinuation[A] type ResultOrContinuation[A any] struct { Value A Error error Continuation *Continuation[A] }
Continuation[A]
- для "трамполайнинга"func StreamFold[A any, B any]( stm Stream[A], onFinish func() io.IO[B], onValue func(a A, tail Stream[A]) io.IO[B], onEmpty func(tail Stream[A]) io.IO[B], onError func(err error) io.IO[B], ) io.IO[B]
IO
type Stream[A any] io.IO[StepResult[A]] type StepResult[A any] struct { Value A HasValue bool // models "Option[A]" Continuation Stream[A] IsFinished bool // true when stream has completed }
IO
порождает либо ошибку, либо результат
def fib(prev: BigInt, b: BigInt): Stream[Pure, BigInt] =
Stream.emit(b) ++ fib(b, prev + b)
val fib01 = fib(0, 1)
assert(fib01.take(5).toList == List(1, 1, 2, 3, 5))
assert(fib01
.map(_.pow(2))
.filter(_ % 2 == 1)
.take(5).toList == List(1, 1, 9, 25, 169)
)
assert(fib01.drop(55).head.toList ==
List(BigInt(225_851_433_717L))
func Fib(prev int, b int) Stream[int] {
return AndThenLazy(Emit(b), func() Stream[int] {
return Fib(b, prev+b)
})
}
var fibs01 = stream.Fib(0, 1)
func TestFibs(t *testing.T) {
powered := stream.Map(fibs01, pow2)
filtered := stream.FilterNot(powered, isEven)
filtered5 := stream.Take(filtered, 5)
expected := []int{1, 1, 9, 25, 169}
assert.ElementsMatch(t, expected, UnsafeStreamToSlice(t, filtered5))
}
hIO := stream.Head(stream.Drop(fib01, 55))
assert.Equal(t, int64(225851433717), UnsafeIO(t, hIO))
Спасибо за внимание
Арсений Александрович Жижелев, Праймтолк / zhizhelev@primetalk.ru