Parsing 在解析表达式的计算中将[IO字符串]转换为IO字符串
在我目前编写的语言中,我试图实现一个函数,该函数根据我已经编写的内容计算整个程序,因为我一次只能执行一条语句。该函数允许我从文件中解析和计算文件 函数Parsing 在解析表达式的计算中将[IO字符串]转换为IO字符串,parsing,haskell,Parsing,Haskell,在我目前编写的语言中,我试图实现一个函数,该函数根据我已经编写的内容计算整个程序,因为我一次只能执行一条语句。该函数允许我从文件中解析和计算文件 函数evalString是问题所在。例如,如果函数的最后一行是runIOThrows$liftM show$evalStatement env(x!!0),则该函数可以完美执行。我觉得应该采取的自然步骤是使用map,但这只会给我[IO String],而不是IO String 如果我返回函数[IO String],但是readStatement函数和e
evalString
是问题所在。例如,如果函数的最后一行是runIOThrows$liftM show$evalStatement env(x!!0)
,则该函数可以完美执行。我觉得应该采取的自然步骤是使用map
,但这只会给我[IO String]
,而不是IO String
如果我返回函数[IO String]
,但是readStatement
函数和evalAndPrint函数存在错误:
----- readStatement -----
Couldn't match type ‘IO’ with ‘[]’
Expected type: [[HStatement]]
Actual type: IO [HStatement]
----- evalAndPrint -----
Couldn't match type ‘[]’ with ‘IO’
Expected type: IO ()
Actual type: [()]
Couldn't match type ‘IO’ with ‘[]’
Expected type: IO String -> [()]
Actual type: String -> IO ()
我得到的印象是,使用map
可以更容易地达到预期效果。如果我按顺序执行每一条语句,那么一切都会完美地工作,那么也许我可以使用map
来评估n-1
语句,然后手动执行n
一条语句
parseProgram :: Parser [HStatement]
parseProgram = spaces *> many (parseEvalHVal <* spaces)
readStatement :: String -> IO [HStatement]
readStatement input = do
program <- readFile input
case parse parseProgram "fyp" program of
Left err -> fail $ show err
Right parsed -> return $ parsed
evalAndPrint :: Env -> String -> IO ()
evalAndPrint env expr = evalString env expr >>= putStrLn
evalString :: Env -> String -> IO String
evalString env expr = do
x <- readStatement expr
putStrLn $ show x
map (\exprs -> runIOThrows $ liftM show $ evalStatement env exprs) x
run :: String -> IO ()
run expr = nullEnv >>= flip evalAndPrint expr
main :: IO ()
main = do
args <- getArgs
run $ args !! 0
runIOThrows :: IOThrowsError String -> IO String
runIOThrows action = runExceptT (trapError action) >>= return . extractValue
parseProgram::Parser[hs语句]
parseProgram=spaces*>many(ParseEvalVal IO[hsStatement]
readStatement输入=do
程序失败$show err
右解析->返回$parsed
evalAndPrint::Env->String->IO()
evalAndPrint env expr=evalString env expr>>=putStrLn
evalString::Env->String->IO String
evalString env expr=do
x runIOThrows$liftM显示$evalStatement环境表达式)x
运行::字符串->IO()
运行expr=nullEnv>>=flip evalAndPrint expr
main::IO()
main=do
args IO字符串
runIOThrows操作=runExceptT(traperor操作)>>=返回。提取值
您可以使用mapM
执行IO
的步骤,然后检索字符串列表:
evalString :: Env -> String -> IO [String]
evalString env expr = do
x <- readStatement expr
putStrLn (show x)
mapM (runIOThrows . liftM show . evalStatement env) x
太好了!我假设
mapM
可以用于处理类型ioa
时需要map的所有情况,如果这有意义的话?@JiangShi FYItraverse
是mapM
的更现代的等价物。如果你想学习其中一种,我建议你使用traverse
,因为它的适用范围更广,而且也有同样的作用。与我对公认答案的评论类似,liftM
是一个古老的遗迹:现代代码使用fmap
或()
。当然,这只是一个风格问题,如果你已经深深习惯了liftM
,那么坚持使用它不会有什么坏处(除了不太经常使用),但是如果你能选择一个来习惯fmap
则更时尚。
evalString :: Env -> String -> IO String
evalString env expr = do
x <- readStatement expr
putStrLn (show x)
concat <$> mapM (runIOThrows . liftM show . evalStatement env) x