Haskell StateT与input的结合

Haskell StateT与input的结合,haskell,monads,monad-transformers,state-monad,Haskell,Monads,Monad Transformers,State Monad,这是一个后续行动。我试图在我的input循环中结合@ErikR的shell 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 <- ge

这是一个后续行动。我试图在我的
input
循环中结合@ErikR的
shell

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
这已经是一个问题了

二,。将每个命令保存到历史记录(自动),并使用特殊命令显示所有以前的命令,例如
histInput
(与
ipython
中的
hist
相同)。另外,保存所有输出结果的历史记录,并使用
historoutput
显示它们。这就是我在这个问题上要做的(只输入当前的历史记录)

三、 参考先前的输入和输出,例如,如果[1]中的
x
,则[1]+2
中的
应替换为
x+2
,同样,也应替换为输出

更新

我尝试合并@ErikR,并暂时禁用了
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
modulemain其中
导入语法
导入解析器
进口评估
进口漂亮
进口柜台
进口管制
进口管制.Monad.Trans
导入System.Console.Haskeline
进口控制单体状态
showStep::(Int,Expr)->IO()
showStep(d,x)=putStrLn((复制d')+“=>”++ppexpr x)
进程::计数器->字符串->输入(StateT[String]IO)()
工艺c线=
如果((长度线)>0)
然后
如果(首行)/=“%”
那就做吧
修改(++[行])
让res=parsexpr行
案件
左错误->输出strln$show错误
右前->做
放(出,~步)=runEval ex
--mapM_uuu显示步骤
out_ps1 c$OUT2 out$show out
否则会
让iout=handle\u命令行
out_ps1 c iout
--TODO:不为空行增加计数器
否则会
输出STRLn“”
Out2Out::String->IO字符串
out2iout s=返回s
输出ps1::计数器->IO字符串->输入(StateT[String]IO)()
out_ps1 c iout=do
输出IO字符串
handle\u cmd line=if line==%hist
然后
evalStateT getHist[]
其他的
返回“未知命令”
getHist::StateT[String]IO字符串
getHist=do
历史
显示i++“:“++”显示h
main::IO()
main=do
c IO()
repl c=evalStateT(runinput defaultSettings(循环c))[]
循环::计数器->输入(StateT[String]IO)()
循环c=do
minput返回()
只需输入->过程c输入>>循环c
getLineIO::(MonadException m)=>IO字符串->输入m(可能是字符串)
getLineIO ios=do
s IO字符串
in_ps1 c=do
设离子=c1
n do{show i++“:“++show h}
在表达式中:
do{hist do{…}
在“getHist”的方程式中:
盖斯特
=do{hist…}

第一个错误是因为您已声明

main :: IO ()
而且

execStateT (...) :: IO [String]

execStateT
返回计算的最终状态,并且您的状态类型为
[String]
。通常情况下,只要不为
main
声明一个类型,并让某些
a
将其推断为
IO a
,就可以解决这个问题。第二个我不确定,但可能是同一件事。

我想猜猜你想做什么

此程序可识别以下命令:

hist        -- show current history
add xxx     -- add xxx to the history list
clear       -- clear the history list
count       -- show the count of history items
quit        -- quit the command loop
节目来源:

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

main :: IO ()
main = evalStateT (runInputT defaultSettings loop) []

loop :: InputT (StateT [String] IO) ()
loop = do
  minput <- getInputLine "% "
  case minput of
      Nothing -> return ()
      Just "quit" -> return ()
      Just input -> process input >> loop

process input = do
  let args = words input
  case args of
    []  -> return ()
    ("hist": _)     -> showHistory
    ("add" : x : _) -> lift $ modify (++ [x]) 
    ("clear": _)    -> lift $ modify (const [])
    ("count": _)    -> do hs <- lift get
                          outputStrLn $ "number of history items: " ++ show (length hs)
    _               -> outputStrLn "???"

showHistory = do
  hist <- lift get
  forM_ (zip [(1::Int)..] hist) $ \(i,h) -> do
    outputStrLn $ show i ++ " " ++ h
import System.Console.Haskeline
导入控制.Monad.Trans.Class
进口控制。单子。跨州。严格
进口管制
main::IO()
main=evalStateT(runinput defaultSettings循环)[]
循环::输入(StateT[String]IO)()
循环=do
minput返回()
只需“退出”->return()
只需输入->流程输入>>循环
过程输入=do
让args=单词输入
案例参数
[]->返回()
(“历史”:-->展示历史
((“添加”:x:\->lift$modify(++[x])
(“清除”:-->lift$modify(const[])
(“计数”:-->hs outputStrLn是吗?”
showHistory=do
历史
outputStrLn$show i++++++++h
您编译的代码,它将
过程定义为:

process :: Counter -> String -> IO ()
要创建具有此签名的
流程版本

Counter -> String -> InputT (StateT [String] IO) ()
只需使用liftIO:

process' :: Counter -> String -> InputT (StateT [String] IO) ()
process' counter str = liftIO $ process counter str

haskeline已经为您实现了命令行历史记录-我知道,请看一下谢谢,但我想自己实现它作为一个练习。如果您想自己实现历史记录,为什么
input
会出现在您的代码中?它取自Stephen Diehl在WYAH中的原始代码。我不需要
input
本身,我只需要获得一个带有自定义提示的输入行,然后使用
getInputLine
,它的类型是
(MonadException m)=>String->input m(可能是String)
。谢谢,第一个错误是通过更改为
main::IO[String]
解决的。我会更新这个问题。非常感谢,我会添加一个关于我真正问题的描述。谢谢,它确实可以编译,但缺乏历史逻辑。您建议如何添加它?具体地说,如果
showHistory
中的
get
不在状态单子中,或者我遗漏了什么,我将如何使用它?我还尝试从
process'
调用
showHist
,但被另一个进程卡住了。
process :: Counter -> String -> IO ()
Counter -> String -> InputT (StateT [String] IO) ()
process' :: Counter -> String -> InputT (StateT [String] IO) ()
process' counter str = liftIO $ process counter str