StateT mit InputT kombinieren

Es ist eine Fortsetzung vondiese Frag. Ich versuche, @ zu kombiniershell von @ ErikR'sAntworte in meinemInputT loop.

main :: IO [String]
main = do
    c <- makeCounter
    execStateT (repl c) []

repl :: Counter -> StateT [String] IO ()
repl c = lift $ runInputT defaultSettings loop
  where
  loop = do
    minput <- getLineIO $ in_ps1 $ c
    case minput of
      Nothing -> lift $ outputStrLn "Goodbye."
      Just input -> (liftIO $ process c input) >> loop

getLineIO :: (MonadException m) => IO String -> InputT m (Maybe String)
getLineIO ios = do
    s <- liftIO ios
    getInputLine s

Und erhalte einen Fehler

Main.hs:59:10:
    Couldn't match type ‘InputT m0’ with ‘IO’
    Expected type: StateT [String] IO ()
      Actual type: StateT [String] (InputT m0) ()
    Relevant bindings include
      loop :: InputT (InputT m0) () (bound at Main.hs:61:3)
    In the expression: lift $ runInputT defaultSettings loop
    In an equation for ‘repl’:
        repl c
          = lift $ runInputT defaultSettings loop
          where
              loop
                = do { minput <- getLineIO $ in_ps1 $ c;
                       .... }

Main.hs:62:5:
No instance for (Monad m0) arising from a do statement
The type variable ‘m0’ is ambiguous
Relevant bindings include
  loop :: InputT (InputT m0) () (bound at Main.hs:61:3)
Note: there are several potential instances:
  instance Monad (Text.Parsec.Prim.ParsecT s u m)
    -- Defined in ‘Text.Parsec.Prim’
  instance Monad (Either e) -- Defined in ‘Data.Either’
  instance Monad Data.Proxy.Proxy -- Defined in ‘Data.Proxy’
  ...plus 15 others
In a stmt of a 'do' block: minput <- getLineIO $ in_ps1 $ c
In the expression:
  do { minput <- getLineIO $ in_ps1 $ c;
       case minput of {
         Nothing -> lift $ outputStrLn "Goodbye."
         Just input -> (liftIO $ process c input) >> loop } }
In an equation for ‘loop’:
    loop
      = do { minput <- getLineIO $ in_ps1 $ c;
             case minput of {
               Nothing -> lift $ outputStrLn "Goodbye."
               Just input -> (liftIO $ process c input) >> loop } }

Der vollständige Code kann gefunden werdenHie, es basiert aufSchreibe dir ein Haskell.

Ich kennehaskelline hat eine eingebaute Unterstützung für die Geschichte, aber ich versuche, sie selbst als Übung zu implementieren.

Sie können jederzeit Ersatz für die Monadentransformatoren vorschlagen, um die gleiche Funktionalität zu erhalten.

Mein echtes Problem

Ich möchte hinzufügenipython wie Fähigkeiten zum Lambda REPL in Write You a Haskell, nämlich:

ICH. Ein Zähler für Ein- und Ausgabe, der in der Eingabeaufforderung angezeigt wird, z. B.

In[1]>
Out[1]>

Das ist schonerledig.

II. Speichern Sie jeden Befehl im Verlauf (automatisch) und zeigen Sie alle vorherigen Befehle mit einem speziellen Befehl an, z.histInput (gleich wiehist imipython). Speichern Sie auch einen Verlauf aller Ausgabeergebnisse und zeigen Sie sie mit @ ahistOutput. Dies ist, was ich in dieser Frage versuche (Eingabeverlauf nur für den Moment).

III. Verweisen auf vorherige Eingaben und Ausgaben, z. wennIn[1] warx, dannIn[1] + 2 sollte durch @ ersetzt werdx + 2 und ebenfalls für die Ausgabe.

Aktualisiere

Ich habe versucht, @ ErikR's @ zu kombinierAntworte und vorübergehend deaktiviertshowStep, kommt mit:

module Main where

import Syntax
import Parser
import Eval
import Pretty
import Counter

import Control.Monad
import Control.Monad.Trans
import System.Console.Haskeline
import Control.Monad.State

showStep :: (Int, Expr) -> IO ()
showStep (d, x) = putStrLn ((replicate d ' ') ++ "=> " ++ ppexpr x)

process :: Counter -> String -> InputT (StateT [String] IO) ()
process c line =
    if ((length line) > 0)
       then
        if (head line) /= '%'
            then do
                modify (++ [line])
                let res = parseExpr line
                case res of
                    Left err -> outputStrLn $ show err
                    Right ex -> do
                        let (out, ~steps) = runEval ex
                        --mapM_ showStep steps
                        out_ps1 c $ out2iout $ show out
        else do
                let iout = handle_cmd line
                out_ps1 c iout

    -- TODO: don't increment counter for empty lines
    else do
      outputStrLn ""

out2iout :: String -> IO String
out2iout s = return s

out_ps1 :: Counter -> IO String -> InputT (StateT [String] IO) ()
out_ps1 c iout = do
      out <- liftIO iout
      let out_count = c 0
      outputStrLn $ "Out[" ++ (show out_count) ++ "]: " ++ out
      outputStrLn ""

handle_cmd :: String -> IO String
handle_cmd line = if line == "%hist"
                     then
                        evalStateT getHist []
                     else
                         return "unknown cmd"

getHist :: StateT [String] IO String
getHist = do
    hist <- lift get
    forM_ (zip [(1::Int)..] hist) $ \(i, h) -> do
                                show i ++ ": " ++ show h

main :: IO ()
main = do
    c <- makeCounter
    repl c

repl :: Counter -> IO ()
repl c = evalStateT (runInputT defaultSettings(loop c)) []

loop :: Counter -> InputT (StateT [String] IO) ()
loop c = do
    minput <- getLineIO $ in_ps1 $ c
    case minput of
      Nothing -> return ()
      Just input -> process c input >> loop c

getLineIO :: (MonadException m) => IO String -> InputT m (Maybe String)
getLineIO ios = do
    s <- liftIO ios
    getInputLine s

in_ps1 :: Counter -> IO String
in_ps1 c = do
    let ion = c 1
    n <- ion
    let s = "Untyped: In[" ++ (show n) ++ "]> "
    return s

was immer noch nicht kompiliert:

Main.hs:59:5:
    Couldn't match type ‘[]’ with ‘StateT [String] IO’
    Expected type: StateT [String] IO String
      Actual type: [()]
    In a stmt of a 'do' block:
      forM_ (zip [(1 :: Int) .. ] hist)
      $ \ (i, h) -> do { show i ++ ": " ++ show h }
    In the expression:
      do { hist <- lift get;
           forM_ (zip [(1 :: Int) .. ] hist) $ \ (i, h) -> do { ... } }
    In an equation for ‘getHist’:
        getHist
          = do { hist <- lift get;
                 forM_ (zip [(1 :: Int) .. ] hist) $ \ (i, h) -> ... }

Antworten auf die Frage(6)

Ihre Antwort auf die Frage