Как стать автором
Обновить

Комментарии 20

Было бы классно, если бы имелся какой-нибудь веб-фреймворк для Haskell, использующий продолжения (Is anyone using delimited continuations to do web development in Haskell?)

Продолжения – шикарная вещь для удобного и быстрого построения веб-логики и интерфейса приложения, сохраняющего состояния. В этом плане себя прекрасно показывает веб-сервер языка Racket.
Не могли бы вы пояснить, что такого шикарного предлагают продолжения веб-разработке?
Можно записать логику с показом множества форм как обычную последовательность действий. Примерно так:

Начинаем нечто
call-cc form1
продолжаем имея результаты form1
call-cc form2
продолжаем уже и с form2

framework обеспечивает возврат после form1/form2.

Я с веб-разработкой не очень знаком, можно каким-нибудь более простым языком?
ПФП #7, страница 130. Лучше читать статью с начала.
Понятно.

> на каждую клиентскую сессию в рантайме развешивается некое дерево замыканий и продолжений, которые держат ссылки на различные объекты, не позволяя мусорщику их подчистить.

> мы не можем нарастить производительность системы добавлением нового сервера с балансировкой веб-запросов в кластере. Потому что все запросы клиента в пределах одной пользовательской сессии должны попадать на ту машину, где она была создана.
Некоторые фреймворки (ЕМНИП в racket) пропихивают продолжения через кукисы, как вы без продолжений будете делать то же с промежуточными данными формы.
Stateful веб-приложения — зло. Стейты интерфейса на продолжениях не исключение. Не нужно городить такой слой абстракций, аукнется.
А в чём их проблема?
Если коротко: использование stateful архитектуры влечет за собой не оправданное в большинстве случаев усложнение архитектуры.

Протокол http по своей натуре stateless. Для имитации сеансового общения с состоянием (сессии) в любом случае приходится делать хаки. Это или проставление специального хедера с идентификатором сессии, либо специальное поле в передаваемых данных, ну или конечно же встроенный механизм на основе кук. Однако нужно понимать, что это скорее для исключительных ситуаций, где без стейта уже никак, например авторизация пользователя. Не зря же существует вообще REST-архитектура.

Что касается стейтовых приложений, то они имеют право на жизнь, но вспомним чем же так хороша REST-архитектура. Это легкое обеспечение отказоустойчивости и масштабируемости. В случае стейтового приложения нужно будет использовать хитроумный механизм репликации состояний между узлами кластера, что является довольно серьезным усложнением инфраструктуры приложения, на которое нельзя идти без веских причин.

Одно дело, если имеем в виду толстое интерпрайзное приложение, в котором до черта многостраничных форм, то тут да, наверное стоит приложение сделать stateful и настравивать репликацию сессий на выбранном аппсервере. Но тут уже сложившийся набор технологий.
Хм… 80% приложений даже в теории никогда не должны вырасти за пределы возможностей одной машины. Кроме того никто не отменял вертикального масштабирования.
Авторитет, безусловно нельзя считать особым аргументом, но вот, что говорит Снойман, автор Yesod (одного из заметных вебных фреймворков на хаскеле)
Все правильно он пишет: продолжения противоречат REST. Нужен или не нужен REST, вопрос уже другой и каждый в зависимости от своих условий должен выбрать сам.
Не понял. В выражении callCC $ \k -> k (чёнибудь) k имеет тип (a -> Cont r b), то есть возвращает продолжение со входом отличным от чёнибудь. При этом возвращаемое замыканием значение имеет тип Cont r a. То есть тип чёнибудь. Получается что типы построенного с помощью k продолжения и продолжения, которое будет возвращено (пипец, мне бы хоть окурочек от того косяка, что это породил) отличаются. Как такое может получиться?
Понял, никто не мешает как-то манипулировать с тем что пришло из продолжения. По способности выедать время хаскель рвёт любую игру как тузик грелку.
После прочтения хочется воскликнуть: о Боже, ну зачем так усложнять простую вещь?
Нет. Ну а к чему минус? Вот смотрите, вызовам с продолжениям в руководстве по lisp уделена пара страничек. И этого достаточно, чтобы понять и пользоваться. В Haskell же монады, мозговыворачивательные ограничения на типы и т.д. Какой смысл в этом? Я вот действительно не понимаю. Тем более, что если судить по Real World Haskell это всё нисколько не упрощает программирование, а только запутывает его. So why so overcomplicated?
square_Cont :: Int -> Cont r Int
-- square_Cont x = return (x*x)
square_Cont = return . join (*)

incr_Cont :: Int -> Cont r Int
-- incr_Cont x = return (x+1)
incr_Cont = return . (+1)

func_Cont :: Int -> Cont r Int
{-
func_Cont x = do inc <- incr_Cont x
                 sq <- square_Cont inc
                 return sq
-}
func_Cont = (square_Cont =<<) . incr_Cont


> Эта программа вычисляет факториал, и если он оказывается больше 9000, возвращает сообщение «OVER 9000», а если нет, то просто его значение.
Эта программа возвращает строку «OVER 9000» для n > 7, а для остальных n возвращает строку с n!..

foo :: Int -> Cont r String
foo s = do (i, back) <- getCC' s
           when (i < 20) $ back (i*2)
           return $ show i


А зачем тут String?
Что такое getCC' и откуда?
Как я вижу, Вы сделали некоторые функции короче. Конечно можно и так, но цель моего «развёрнутого» кода в том, что можно проследить взаимосвязь между использованием продолжений как обычных функций, и как монад.
Сравните:
func_cps :: Int -> (Int -> r) -> r
func_cps x k = incr_cps x $ \inc ->
               square_cps inc $ \sq ->
               k sq
и
func_Cont :: Int -> Cont r Int
func_Cont x = do inc <- incr_Cont x
                 sq <- square_Cont inc
                 return sq

Да, эта программа не учитывает само значение факториала, просто для n>7 факториал больше 9000.

String тут потому, что в конце мы возвращаем show i, т.е. строковое представление числа.

getCC' — это вариант getCC, с помощью которого можно ещё и передать состояние. Грубо говоря, getCC' возвращает нам пару из текущего состояния вычисления (число в данном случае) и функции, которая берёт новое состояние и возвращает вычисление в заданную точку (как goto). В статье есть больше про getCC и getCC' + объяснение как они работают.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории