Haskell 中的 '\b' 字符如何工作?

How does the '\b' character in Haskell work?

来源:赫顿,格雷厄姆。 “在 Haskell 中编程”(第 180 页)

  1. Using getCh, define an action readLine :: IO String that behaves in the same way as getLine, except that it also permits the delete key to be used to remove characters.

Hint: the delete character is ’\ DEL’, and the control character for moving the cursor back one space is ’\b’.

我用一个 '\b' 字符解决了这个练习,但在网上发现求解器使用了两个字符。为什么这个问题的求解器使用 "\b \b" 而不是 "\b" ?似乎是一个错字,但我不确定。我发现它适用于三个 '\b' 个字符。

这个角色如何运作?

import System.IO

getCh :: IO Char
getCh = do
  hSetEcho stdin False
  x <- getChar
  hSetEcho stdin True
  return x

readLine :: IO String
readLine = readLine' ""

readLine' :: String -> IO String
readLine' xs = do
  x <- getCh
  case x of
    '\n' -> do
      putChar '\n'
      return xs
    '\DEL' ->
      if null xs
        then readLine' ""
        else do
          putStr "\b \b"
          readLine' (init xs)
    _ -> do
      putChar x
      readLine' (xs ++ [x])

\b 将光标向后移动一个字符,但不会将其删除(至少在大多数终端上不会)。例如,字符串 abcde\b 将显示为 abcde,而字符串 abcde\bf 将显示为 abcdf。这就是为什么序列 \b \b 明确地用 space 覆盖最后一个字符,然后再次将光标移回。

如果您只使用 "\b",光标会向左移动,但不会删除那里看到的字符,直到您用新的键输入覆盖它。比如FOO会结束你up with fo⁁o,但这是误导:如果你 按下另一个字母键,但立即按下 ,那么看起来结果仍然是 foo,而实际上它只是 fo.

为了避免这种情况,解决方案"\b \b"向左移动,用space覆盖字符以可视化删除它,然后立即再次向左移动。这与向左移动一次并就地删除字符具有相同的效果。