Category: рукоделие

Category was added automatically. Read all entries about "рукоделие".

Scalaz для сельских механизаторов - 2

В предыдущей части я немного увлёкся и начал рассказывать про стрелки Клейсли, хотя прежде следует рассказать, зачем нужна композиция "монадичных" функций (т.е. тех, которые возвращают монаду).

Любые замечания и исправления приветствуются.

--

Композиция нечистых функций, Ленивость и Separation of Concerns

Итак в предыдущей части мы увидели, как можно превратить "нечистую" функцию в "чистую", если переписать её так, чтобы она возвращала монаду. Например функция, которая может вернуть ошибку типа E вместо значения типа А, должна возвращать E\/A. По типу возвращаемой монады легко определить, что за "эффект" производит функция, и трудно его проигноировать в коде.

Мы также видели, что функции, которые возвращает одну и ту же монаду легко "композируются"
val amb: A => M[B] = ...
val bmc: B => M[C] = ...
val amc: A => M[C] = a => amb(a) flatMap bmc
Однако возникает вопрос: а зачем композировать amb и bmc и создавать новую функцию amc. Не является ли эта функция amc лишней ?

Для ответа рассмотрим конкретный пример: допустим, нам нужно написать библиотечку для вызова REST сервисов. У нас есть функция для простого синхронного HTTP вызова:
val invoke: HttpRequest => Throwable\/HttpResponse = ...
У нас также есть функции:
val encodeA: А => HttpRequest = ...
val encodeC: C => HttpRequest = ...
а также:
val decodeB: HttpResponse => B = ...
val decodeD: HttpRepsonse => D = ...
Нам удобно их скомпозировать, чтобы получить функции вида
type Service[X, Y] = X => Throwable\/Y
которые станут интерфейсом нашей библиотечки.
val ab: A => Throwable\/B = a => 
  for {
    req  <- encodeA(a).right; 
    resp <- invoke(req); 
    b    <- decodeB(resp) 
  } yield b

val bc: B => Throwable\/C = ...
Если требуется вызвать сначала ac, а потом bc, то это можно скомпозировать так:
val ac: A => Throwable\/C = a => for { b <- ab(a); c <- bc(b) } yield c
Теперь для аппликации, которая вызывает эти интерфейсы, можно написать одну универсальную функцию invokeAndHandleErrors[X, Y], которая исполняет X => Throwable\/Y и обрабатывает Throwables. Обработка Throwable т.е. обработка эффекта, специфична именно для вызывающей стороны: например запись в лог, сообщение системе мониторинга и проч. Вся эта обработка ортогонально нашей библиотечке.

Таким образом с помощью композиции функций мы смогли разделить сами по себе REST вызовы и обработку ошибок этих вызовов с использованием специфичных для вызывающей стороны средств.

(no subject)

Решил написать зачем нужны type class'ы на Скале по мотивам одного постинга

Условие задачи

Итак, допустим, я пишу на джаве простую аппликацию, типа магазина в интернете
и написал свою модель предметной области в виде классов Customer, Product, Order и др.

Теперь возникает задача: посылать и принимать об'екты этих классов по сети.
Для чего требуется писать/читать об'екты этих классов в/из буфера.

Давайте для простоты возьмем один класс Order и посмотрим как писать и читать об'екты этого класса.Collapse )