如何让行处理的解释器函数实现交互式即时响应?
问题描述
我的解释器支持以下操作:
up(递增y坐标)down(递减y坐标)left(递减x坐标)right(递增x坐标)printX(打印x坐标)printY(打印y坐标)
当前的Haskell实现如下:
interpreterHelper :: [String] -> Int -> Int -> Int -> [String] -> [String] interpreterHelper cmds index x y output | index == length (cmds) = reverse output | (cmds !! index) == "up" = interpreterHelper cmds (index + 1) x (y + 1) output | (cmds !! index) == "down" = interpreterHelper cmds (index + 1) x (y - 1) output | (cmds !! index) == "left" = interpreterHelper cmds (index + 1) (x - 1) y output | (cmds !! index) == "right" = interpreterHelper cmds (index + 1) (x + 1) y output | (cmds !! index) == "printX" = interpreterHelper cmds (index + 1) x y (show x : output) | (cmds !! index) == "printY" = interpreterHelper cmds (index + 1) x y (show y : output) interpreter :: [String] -> [String] interpreter cmds = interpreterHelper cmds 0 0 0 []
练习要求通过interact (unlines . interpreter . lines)实现交互功能,但目前无法生效。需要修改代码,实现输入printY后立即返回当前y坐标值的交互式效果。
解决方案
原代码的核心问题是一次性处理所有输入、统一输出结果,无法做到输入一行就即时响应。要实现交互式,需改为逐行处理并即时输出,同时保留x、y的状态。
下面是修改后的实现:
import Control.Monad (foldM) main :: IO () main = do let initialState = (0, 0) :: (Int, Int) input <- getContents foldM processLine initialState (lines input) >> return () where processLine (x, y) cmd = case cmd of "up" -> return (x, y + 1) "down" -> return (x, y - 1) "left" -> return (x - 1, y) "right" -> return (x + 1, y) "printX" -> putStrLn (show x) >> return (x, y) "printY" -> putStrLn (show y) >> return (x, y) _ -> return (x, y) -- 忽略未知命令
关键修改说明
- 状态传递:用
(Int, Int)保存当前x、y坐标,通过foldM在每一行命令处理后传递更新后的状态。 - 即时输出:遇到
printX/printY时,直接调用putStrLn输出结果,无需等待所有输入处理完成。 - IO Monad:因为需要实时输出,处理逻辑必须放在IO Monad中,替代原有的纯函数式列表转换。
原有的interact (unlines . interpreter . lines)模式是纯函数式的,会先读取全部输入再生成输出,无法满足即时交互需求。改用上述基于IO的逐行处理后,每输入一行命令,程序会立即处理并输出结果。
内容的提问来源于stack exchange,提问作者coderodde
相关产品推荐
相关产品推荐

