PureScript:如何从标准输入读取字符串并累加积分?
PureScript石头剪刀布积分累加问题解决方案
方案一:在main作用域直接读取用户输入
如果不需要持续异步输入监听,可以用同步读取方法直接在main里获取输入,通过循环维护总积分:
import Node.ReadLine (readLineSync, close) import Effect.Class.Console (log) -- 示例:简化的单次对局积分计算逻辑 calculateResult :: String -> Int calculateResult input = case input of "石头" -> 1 "剪刀" -> 0 "布" -> -1 _ -> 0 main :: Effect Unit main = do log "石头剪刀布游戏开始,输入'退出'结束游戏" loop 0 where loop :: Int -> Effect Unit loop total = do input <- readLineSync "请输入你的选择(石头/剪刀/布/退出):" if input == "退出" then do log $ "游戏结束,总积分:" <> show total close else do let change = calculateResult input let newTotal = total + change log $ "本次积分变化:" <> show change <> ",当前总积分:" <> show newTotal loop newTotal
readLineSync会阻塞直到用户输入,直接在main的循环函数里维护总积分,逻辑简单直观。
方案二:在lineHandler中累加积分
方法1:使用可变引用(Ref)
针对异步输入监听场景(比如onLine回调),用Effect.Ref创建可变状态容器,在回调中读写总积分:
import Node.ReadLine (createInterface, close, onLine, setPrompt, prompt, stdin, stdout) import Effect.Ref (Ref, newRef, readRef, writeRef) import Effect.Class.Console (log) calculateResult :: String -> Int calculateResult input = case input of "石头" -> 1 "剪刀" -> 0 "布" -> -1 _ -> 0 main :: Effect Unit main = do -- 创建初始积分为0的可变引用 pointsRef <- newRef 0 rl <- createInterface { input: stdin, output: stdout } setPrompt rl "请输入你的选择(石头/剪刀/布),输入'q'退出:" prompt rl -- 监听输入事件 onLine rl \input -> do if input == "q" then do finalPoints <- readRef pointsRef log $ "游戏结束,总积分:" <> show finalPoints close rl else do let change = calculateResult input current <- readRef pointsRef let newPoints = current + change writeRef pointsRef newPoints log $ "本次积分变化:" <> show change <> ",当前总积分:" <> show newPoints prompt rl -- 监听退出事件 onClose rl \_ -> log "已退出游戏"
Ref是Effect上下文的可变状态容器,readRef读取当前值,writeRef更新值,可在异步回调中安全共享和修改状态。
方法2:使用State Monad结合递归
State Monad将状态与计算逻辑绑定,每次处理输入时基于当前状态生成新状态和输出,结合递归维护积分:
import Node.ReadLine (createInterface, close, readLine, setPrompt, prompt, stdin, stdout) import Effect.Class.Console (log) import Control.Monad.State (State, runState, modify, get) -- 单次输入的State逻辑:处理选择、更新积分、返回提示文本 handleTurn :: String -> State Int String handleTurn input = do let change = case input of "石头" -> 1 "剪刀" -> 0 "布" -> -1 _ -> 0 -- 修改状态(累加积分) modify (_ + change) -- 获取更新后的状态 currentPoints <- get pure $ "本次积分变化:" <> show change <> ",当前总积分:" <> show currentPoints main :: Effect Unit main = do rl <- createInterface { input: stdin, output: stdout } setPrompt rl "请输入你的选择(石头/剪刀/布),输入空行退出:" prompt rl -- 递归循环:传入当前积分,处理下一次输入 let gameLoop :: Int -> Effect Unit gameLoop currentPoints = do maybeInput <- readLine rl case maybeInput of Just input -> do -- 运行State逻辑,得到输出文本和新积分 let (output, newPoints) = runState (handleTurn input) currentPoints log output prompt rl gameLoop newPoints Nothing -> do log $ "游戏结束,总积分:" <> show currentPoints close rl -- 初始积分为0,启动循环 gameLoop 0
handleTurn封装状态更新逻辑,runState将其与当前积分结合,得到新积分和输出。通过递归调用gameLoop,每次传入更新后的积分实现状态累加。
内容的提问来源于stack exchange,提问作者Alex
相关产品推荐
相关产品推荐

