this question의 후속 조치입니다. 나는 shell
을 @ ErikR의 answer에서 내 InputT
루프에 결합하려고합니다.StateT와 InputT를 결합하십시오
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
그리고 오류
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 } }
전체 코드를 얻기가 here을 찾을 수 있습니다, 그것은 Write you a haskell을 기반으로.
나는 haskelline
에 내역이 내장되어 있음을 알고 있지만 연습으로 직접 구현하려고합니다.
동일한 기능을 얻기 위해 모나드 변환기의 대체품을 자유롭게 제안 할 수 있습니다.
내 진짜 문제
내가 쓰기에 람다 REPL에 기능, 즉 당신은 하스켈처럼ipython
을 추가 할
:
이I. 입력 및 출력에 대한 카운터가 나타납니다 즉,
In[1]>
Out[1]>
이것은 이미 done입니다.
II. 각 명령을 기록에 저장 (자동)하고 특수 명령을 사용하여 이전 명령을 모두 표시합니다 (예 : histInput
(hist
은 ipython
과 동일). 또한 모든 출력 결과의 내역을 저장하고 histOutput
을 사용하여 표시하십시오. 이것은 내가이 질문 (입력 히스토리에 대해서만 잠시 동안)에서하려고하는 것입니다.
III. 이전의 입력 및 출력을 참조하십시오. In[1]
이 x
인 경우 In[1] + 2
은 x + 2
으로, 출력용으로는 마찬가지입니다.
업데이트
나는 ErikR의 answer @ 결합하려고했습니다, 일시적으로는 함께 올라오고, showStep
을 사용할 수 없습니다 : 아직 컴파일되지 않는
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
:
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) -> ... }
haskeline 이미 당신을 위해 명령 줄 역사를 구현 -에서 [사용 예]를 살펴 (이 https://hackage.haskell.org/ package/haskeline-0.7.2.3/docs/System-Console-Haskeline.html) – ErikR
고마워, 알아,하지만 운동으로 직접 구현하고 싶다. – dimid
히스토리를 직접 구현하려면 왜 코드에 'InputT'가 표시됩니까? – ErikR