You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 06:21:29