Это Габриэль, разместивший Pipes. Я работал с Паоло, и у нас в работе есть более элегантная реализация, которая является еще более мощной и безопасной для типов, чем его первоначальное предложение. Краткий ответ на ваш вопрос заключается в том, что окончательная реализация представляет собой расширенный набор исходных каналов, и вы можете написать тот же код, что и раньше, с идентичным поведением и семантикой.
Я могу даже резюмировать это довольно просто здесь. Операторы Await и yield — это единственные способы, которыми канал может отказаться от управления, поэтому мы прикрепляем к каждому из них запасной вариант, если восходящий или нисходящий канал завершается. Резервный вариант навсегда понижает качество канала, и он больше не может повторять неудачное действие. Неудачное ожидание понижает рейтинг канала до производителя, а неудачный выход понижает канал до потребителя. Если производитель не выдает или потребитель не ожидает, они понижаются до базовой монады, которая больше не может дать сбой.
Потребители и производители теперь являются отдельными типами и не подвергаются воздействию. Они такие же, как тип конвейера, за исключением отсутствия конструктора Await или Yield. Это необходимо, по крайней мере, для типа производителя, поскольку для каналов не существует входного типа, который может запрещать операторы ожидания.
Операторы await и yield по умолчанию завершаются в качестве резервного поведения, что является тем же поведением, что и раньше. Await и yield будут классифицированы для работы в более ранних состояниях, которые их поддерживают. Однако теперь вы можете при желании указать свой собственный запасной вариант, как только мы придумаем более привлекательное имя, чем tryAwait или tryYield.
Мне все еще нужно убедиться, что Pipes все еще образуют категорию с этим расширением, но это кажется весьма вероятным. Он также на 100% безопасен для типов и использует типы для принудительного перехода на более раннюю версию, а не логические значения и проверенный программистом инвариант.
Редактировать: некоторый работающий код, чтобы подогреть ваш аппетит (ознакомьтесь с веткой «try» из репозитория github, чтобы использовать расширение):
printer = forever $ await >>= lift . print
take' n = replicateM_ n $ await >>= yield
fromList' = mapM_ (yieldOr (lift $ putStrLn "Undelivered elements))
diagnose = forever $ do
x <- awaitOr (lift $ putStrLn "Await failed")
yieldOr (lift $ putStrLn "Yield failed") x
> runPipe $ printer <+< take' 3 <+< diagnose <+< fromList [1..10]
1
2
3
Yield failed
Undelivered elements
> runPipe $ printer <+< take' 10 <+< diagnose <+< fromList [1..3]
1
2
3
Await failed
person
Gabriel Gonzalez
schedule
05.02.2012