Интерпретация монады без телетайпа в монаде RWS - PullRequest
0 голосов
/ 19 октября 2018

В настоящее время я изучаю бесплатные монады, и я играл, наверное, с самым простым и распространенным примером - Teletype:

{-# LANGUAGE DeriveFunctor #-}

import Control.Monad.Free

data TeletypeF a = Put String a
                 | Get (String -> a)
    deriving Functor

type Teletype = Free TeletypeF

Многие учебные пособия интерпретируют Teletype программы в IO монада.Например:

-- Utilities
get   = liftF $ Get id
put s = liftF $ Put s ()

-- Sample programs
echo :: Teletype ()
echo = do word <- get
          if word == "\04"  -- Ctrl-D
          then return ()
          else put word >> echo

hello :: Teletype ()
hello = do put "What is your name?"
           name <- get
           put "What is your age?"
           age <- get
           put ("Hello, " ++ name ++ "!")
           put ("You are " ++ age ++ " years old!")

-- Interpret to IO
interpIO :: Teletype a -> IO a
interpIO = foldFree lift
    where
        lift (Put s a) = putStrLn s >> return a
        lift (Get f)   = getLine >>= return . f

Я пытался интерпретировать это в другой монаде, а именно в монаде RWS .Эта идея была мотивирована последним упражнением из этого задания .Я использую тип данных RWS для извлечения входных данных из части Reader и накопления выходных данных в части State.Но, к сожалению, я не могу заставить его работать.Вот моя попытка:

import Control.Monad.Trans.RWS.Lazy hiding (get, put)

type TeletypeRWS = RWS [String] () [String]

-- Interpret to TeletypeRWS
interpRWS :: Teletype a -> TeletypeRWS a
interpRWS = foldFree lift
    where
        lift (Put s a) = state (\t -> ((), t ++ [s])) >> return a
        lift (Get f)   = reader head >>= local tail . return . f  -- This is wrong

mockConsole :: Teletype a -> [String] -> (a, [String])
mockConsole p inp = (a, s)
    where
        (a, s, _) = runRWS (interpRWS p) inp []

При запуске TeletypeRWS «программ» первое значение в окружении не удаляется:

*Main> mockConsole hello ["john", "18"]
((),["What is your name?","What is your age?","Hello, john!","You are john years old!"])

Я немного обеспокоеноб обновлении Reader, но я не знаю, как еще я могу получить доступ к следующему значению в списке.Тип TeletypeRWS был выбран на основе вышеупомянутого упражнения, поэтому я предполагаю, что должна быть возможность реализовать interpRWS.

1 Ответ

0 голосов
/ 19 октября 2018

Мы не можем использовать foldFree: оно должно быть параметрическим в продолжении, поэтому мы не можем применить local там.Напротив, iterM явно дает нам фактическое продолжение без обобщения, так что это будет работать.

interpRWS = iterM lift where
  lift (Put s a) = modify (\t -> t ++ [s]) >> a
  lift (Get f)   = reader head >>= local tail . f
...