将StateT与InputT结合起来 [英] combining StateT with InputT

查看:88
本文介绍了将StateT与InputT结合起来的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是此问题的后续行动。我试图在@ ErikR的 answer 中结合 shell 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
无 - >提升$ outputStrLn再见。
只需输入 - > (liftIO $ process c input)>>循环

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

获取错误

  Main.hs:59:10:
Couldn' 'Input'与'IO'的匹配类型
预期类型:StateT [String] IO()
实际类型:StateT [String](InputT m0)()
相关绑定包括
loop :: InputT(InputT m0)()(在Main.hs:61:3处绑定)
在表达式中:lift $ runInputT defaultSettings loop
在'repl'等式中:
repl c
= lift $ runInputT defaultSettings loop
where
loop
= do {minput< - getLineIO $ in_ps1 $ c;
....}

Main.hs:62:5:
由do语句引起的(Monad m0)没有实例
类型变量'm0 '不明确
相关绑定包括
loop :: InputT(InputT m0)()(绑定在Main.hs:61:3)
注意:有几个潜在的实例:
实例Monad(Text.Parsec.Prim.ParsecT sum)
- 在'Text.Parsec.Prim'中定义
实例Monad(或e) - 在'Data.E'中定义
实例Monad Data.Proxy.Proxy - 在'Data.Proxy'中定义
...另外15个
在'do'块的结尾处:minput< - getLineIO $ in_ps1 $ c
在表达式中:
do {minput< - getLineIO $ in_ps1 $ c;
的情况下输入为{
Nothing - >提升$ outputStrLn再见。
只需输入 - > (liftIO $ process c input)>>循环}}
在'循环'的等式中:
循环
= do {minput< - getLineIO $ in_ps1 $ c;
的情况下输入为{
Nothing - >提升$ outputStrLn再见。
只需输入 - > (liftIO $ process c input)>>循环}}

完整的代码可以在这里,它基于给你写个哈斯克尔

我知道 haskelline 内置了对历史的支持,但我试图自己实现它一个练习。

随意为monad变换器提供相同功能的替换。



我的真正问题



我想为lambda REPL添加 ipython 给你写一个Haskell,即:

I。输入和输出计数器,将出现在提示符中,即

  In [1]> 
出[1]>

这已经是 done

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



三。参考先前的输入和输出,例如如果 In [1] x ,则 In [1] + 2 应该被 x + 2 取代,输出也是如此。



更新



我试图合并@ ErikR的answer ,并临时禁用 showStep ,并提供:

 模块Main其中

import语法
导入解析器
导入评估
import Pretty
导入计数器

导入Control.Monad
导入Control.Monad.Trans
导入System.Console.Haskeline
导入Control.Monad.State

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

process :: Counter - >字符串 - > InputT(StateT [String] IO)()
process c line =
if((length line)> 0)
then
if(head line)/ ='% '
然后做
修改(++ [line])
let res = parseExpr行
案例res
Left err - > outputStrLn $ show err
右前 - > 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:不要为空行增加计数器
else do
outputStrLn

out2iout: :字符串 - > IO字符串
out2iout s =返回s

out_ps1 ::计数器 - > IO字符串 - > 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字符串
handle_cmd行= if行==%hist
然后
evalStateT getHist []
else
返回未知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
Nothing - > return()
只需输入 - >处理c输入>>循环c

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

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

仍然无法编译:

  Main.hs:59:5:
无法将类型'[]'与'StateT [String] IO'
预期类型:StateT [String] IO字符串
实际类型:[()]
在'do'块的标记中:
forM_(zip [(1 :: Int) ..] hist)
$ \(i,h) - > do {show i ++:++ show h}
在表达式中:
do {hist< - lift get;
forM_(zip [(1 :: Int)..] hist)$ \(i,h) - > do {...}}
在'getHist'的等式中:
getHist
= do {hist< - lift get;
forM_(zip [(1 :: Int)..] hist)$ \(i,h) - > ...}


解决方案

猜测你在做什么。



这个程序可以识别下列命令:

  hist  - 显示当前历史记录
添加xxx - 将xxx添加到历史记录列表
清除 - 清除历史记录列表
count - 显示历史记录的数量
quit - 退出命令循环

程序源代码:

  import System.Console.Haskeline 
import Control.Monad.Trans.Class
import Control.Monad.Trans.State.Strict
import Control.Monad
$ b $ main :: IO()
main = evalStateT(runInputT defaultSettings loop)[]

loop :: InputT(StateT [String ] IO)()
loop = do
minput< - getInputLine%
case
Nothing - > return()
只是退出 - > return()
只需输入 - >过程输入>>循环

过程输入=做
让args =字输入
案例参数
[] - > return()
(hist:_) - > showHistory
(add:x:_) - > lift $ modify(++ [x])
(clear:_) - > lift $ modify(const [])
(count:_) - > do hs< - lift get
outputStrLn $历史项目数量:++ show(length hs)
_ - > outputStrLn???
$ b showHistory = do
hist< - lift得到
forM_(zip [(1 :: Int)..] hist)$ \(i,h) - > ;做
outputStrLn $ show i ++++ h


It is a follow-up to this question. I'm trying to combine shell from @ErikR's answer in my InputT 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

And getting an error

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 } }

The full code can be found here, it's based on Write you a haskell.

I know haskelline has a built-in support for history, but I'm trying to implement it myself as an exercise.

Feel free to suggest replacements for the monad transformers to get the same functionality.

My Real Problem

I'd like to add ipython like capabilities to the lambda REPL in Write You a Haskell, namely:

I. A counter for input and output, that will appear in the prompt, i.e

In[1]>
Out[1]>

This is already done.

II. Save each command to history (automatically), and display all previous commands using a special command, e.g. histInput (same as hist in ipython). Also, save a history of all output results and display them using histOutput. This is what I'm trying to do in this question (input history only for the moment).

III. Reference previous inputs and outputs, e.g. if In[1] was x, then In[1] + 2 should be substituted by x + 2, and likewise for the output.

Update

I've tried to combine @ErikR's answer, and temporarily disabled showStep, coming up with:

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

which still doesn't compile:

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) -> ... }

解决方案

I'm going to take a guess at what you are trying to do.

This program recognizes the following commands:

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

Program source:

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

这篇关于将StateT与InputT结合起来的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆