Возможна ли труба с ограничением доходности на одного ожидания?

Я работаю с дудками-4.0.0. В этой библиотеке количество выходов в нисходящем направлении, которое делает канал, в общем случае не связано с количеством ожидающих в восходящем потоке.

Но предположим, что я хотел построить ограниченный канал, который обеспечивал выполнение одного и только одного выхода для каждого await, и в то же время был в состоянии упорядочить эти типы каналов, используя monadic (>>=).

Я заметил, что в двунаправленном случае каждое значение, запрашиваемое прокси-сервером в восходящем направлении, сопоставляется со значением, отправленным обратно. Так что, возможно, я ищу функцию типа Proxy a' a () b m r -> Pipe a (Either b a') m r это "отражает" значения, идущие вверх по течению, превращая их в дополнительную доходность вниз по течению. Или, менее обычно, Client a' a -> Pipe a a', Возможна ли такая функция?

2 ответа

Решение

Вы определенно не хотите использовать pipes за это. Но то, что вы можете сделать, это определить ограниченный тип, который делает это, выполнить все ваши соединения и логику в этом ограниченном типе, а затем преобразовать его в Pipe когда вы сделали.

Тип вопроса, который вы хотите, это, который похож на netwireWire:

{-# LANGUAGE DeriveFunctor #-}

import Control.Monad.Trans.Free  -- from the 'free' package

data WireF a b x = Pass (a -> (b, x)) deriving (Functor)

type Wire a b = FreeT (WireF a b)

Это автоматически монада и монадный трансформатор, так как он реализован с точки зрения FreeT, Тогда вы можете реализовать эту удобную операцию:

pass :: (Monad m) => (a -> b) -> Wire a b m ()
pass f = liftF $ Pass (\a -> (f a, ()))

... и собирать пользовательские провода, используя монадический синтаксис:

example :: Wire Int Int IO ()
example = do
    pass (+ 1)
    lift $ putStrLn "Hi!"
    pass (* 2)

Затем, когда вы закончите соединять вещи с этим ограниченным Wire типа вы можете продвинуть его к Pipe:

promote :: (Monad m) => Wire a b m r -> Pipe a b m r
promote w = do
    x <- lift $ runFreeT w
    case x of
        Pure r -> return r
        Free (Pass f) -> do
            a <- await
            let (b, w') = f a
            yield b
            promote w'

Обратите внимание, что вы можете определить идентификатор и состав провода и провода:

idWire :: (Monad m) => Wire a a m r
idWire = forever $ pass id

(>+>) :: (Monad m) => Wire a b m r -> Wire b c m r -> Wire a c m r
w1 >+> w2 = FreeT $ do
    x <- runFreeT w2
    case x of
        Pure       r   -> return (Pure r)
        Free (Pass f2) -> do
            y <- runFreeT w1
            case y of
                Pure       r   -> return (Pure r)
                Free (Pass f1) -> return $ Free $ Pass $ \a ->
                        let (b, w1') = f1 a
                            (c, w2') = f2 b
                        in  (c, w1' >+> w2')

Я уверен, что они образуют Category:

idWire >+> w = w

w >+> idWire = w

(w1 >+> w2) >+> w3 = w1 >+> (w2 >+> w3)

Кроме того, я уверен, что promote подчиняется следующим законам функторов:

promote idWire = cat

promote (w1 >+> w2) = promote w1 >-> promote w2

У меня такое чувство, что это будет очень трудно сделать, если не сказать невозможно. Вы можете не только писать производителей и потребителей полными сложных циклов, но и монадический интерфейс определяет, что поток управления потребителя может зависеть от значений, которые он получает от производителя.

consumer = do
  n <- await
  for i in 1..n do
     m <- await
     print m

Будет очень трудно кодировать типы производителей: "это создает N + 1 чисел, где N - значение первого полученного числа".


Возвращаясь к теме, я думаю, что у вас может быть больше шансов, если вы будете использовать свои собственные комбинаторы вместо базового монадического интерфейса для каналов. Например, библиотека веб-маршрутов бумеранга использует набор комбинаторов для одновременной сборки кода, который выполняет преобразование (Route -> URL), и кода, который выполняет преобразование (URL -> Route), таким образом гарантируя, что они совместимы и обратны. друг друга.

Другие вопросы по тегам