Как мне выйти из цикла в Haskell?

текущая версия учебника по трубам, использует следующие две функции в одном из примеров:

 stdout :: () -> Consumer String IO r
 stdout () = forever $ do
     str  Producer String IO ()
 stdin () = loop
   where
     loop = do
         eof 

Ответы на вопрос(4)

Я предпочитаю следующее:

import Control.Monad
import Control.Monad.Trans.Either   

loop :: (Monad m) => EitherT e m a -> m e
loop = liftM (either id id) . runEitherT . forever

-- I'd prefer 'break', but that's in the Prelude
quit :: (Monad m) => e -> EitherT e m r
quit = left

Вы используете это так:

import Pipes
import qualified System.IO as IO

stdin :: () -> Producer String IO ()
stdin () = loop $ do
    eof <- lift $ lift $ IO.hIsEOF IO.stdin
    if eof
    then quit ()
    else do
        str <- lift $ lift getLine
        lift $ respond str

Увидетьэтот блог где я объясняю эту технику.

Единственная причина, по которой я неИспользование этого учебника заключается в том, что я считаю его менее удобным для начинающих.

 hugomg24 июн. 2013 г., 08:03
Похоже, нам нужно было добавить дополнительный уровень "лифт" на все предыдущие монадические операции. Можем ли мы обойти это или это фундаментальное ограничение такого решения на базе трансформаторов? Я понимаю, что в отличие от цикла while,quit должен также работать, когда глубоко вложенный или в других функциях, но я бы нене было бы удобно добавлять эти подъемники, это был единственный путь. (И я определенно согласен с тем, что нет необходимости усложнять вещи в настоящем учебнике - просто это оказалось хорошим примером того, о чем я думал)
 Gabriel Gonzalez24 июн. 2013 г., 21:44
@missingno Мое эмпирическое правило - использовать это решение только тогда, когдаloop решение слишком громоздкое (т. е. есть много дел, которые зацикливаются, и только один случай, который выходит).

импорт System.Exitи использоватьвыход с ExitSuccess

Например. if (input == 'q') затем выйдите с помощью ExitSuccess, иначе выведите 5 (что угодно)

Решение Вопроса

Похоже на работу для:whileM_

stdin () = whileM_ (lift . fmap not $ IO.hIsEOF IO.stdin) (lift getLine >>= respond)

или, используя do-notation, аналогично исходному примеру:

stdin () =
    whileM_ (lift . fmap not $ IO.hIsEOF IO.stdin) $ do
        str <- lift getLine
        respond str

monad-loops Пакет предлагает такжеwhileM который возвращает список промежуточных результатов вместо игнорирования результатов повторного действия и других полезных комбинаторов.

 Daniel Fischer23 июн. 2013 г., 21:41
О, так много за доверие к аналогии с именем. Немонадическийuntil отbase проверяет первым.
 hugomg23 июн. 2013 г., 21:34
whileM_ кажется, делает то же самое, но с параметрами вобычный" порядок. Это именно то, что я искал.
 Daniel Fischer23 июн. 2013 г., 21:36
В некотором смысле,whileM_Порядок аргументов более естественен. Однако для этого нужна инверсия теста, подумал ясделай что-нибудь до конца более естественно чемпока (не EOF) что-то делать, Личное предпочтение.
 hugomg23 июн. 2013 г., 21:40
Я также только что заметил, что пока M_ не проверяет условие после тела цикла. Это будет иметь другое поведение, чем оригинальный код.

перерыв", Более того, ваш пример уже представляет собой небольшой блок, который будет использоваться в более сложном коде.

Если хочешь остановитьсяизготовление струн " это должно поддерживаться вашей абстракцией. То есть немного "Managment» из "трубы» используя специальную монаду вConsumer и / или другие монады, связанные с этим.

 hugomg23 июн. 2013 г., 21:59
Не знаю, я чувствую, что это скорее вопрос общего потока управления, чем вопрос, относящийся к конкретным каналам. И, безусловно, существует неявный поток управления, если мы имеем дело с монадическим кодом.
 ony23 июн. 2013 г., 22:14
@missingno, монады - явный поток, описанный в терминах языка. Большинство императивных языков имеют неявный поток. Когда ты'Я буду без сахараdo нотация выУвидим точное объединение монад. То же самое со многими другими абстракциями, которые описывают некоторыепоток выполнения / синтаксический анализ / генерация / расчет / и т. д. ", Все они описаны в Haskell. В то время как сам язык применяет не такой строгий порядок исполнения (ленивый - это единственное правило, на которое вы можете ретранслироваться).

Ваш ответ на вопрос