看问题:通常,在交互式 Haskell 环境中,非拉丁 Unicode 字符(构成结果的一部分)被转义打印,即使语言环境允许此类字符(与通过 putStrLn
直接输出相反, putChar
看起来不错且可读)--示例显示 GHCi 和 Hugs98:
$ ghci
GHCi, version 7.0.1: http://www.haskell.org/ghc/ :? for help
Prelude> "hello: привет"
"hello: \1087\1088\1080\1074\1077\1090"
Prelude> 'Я'
'\1071'
Prelude> putStrLn "hello: привет"
hello: привет
Prelude> :q
Leaving GHCi.
$ hugs -98
__ __ __ __ ____ ___ _________________________________________
|| || || || || || ||__ Hugs 98: Based on the Haskell 98 standard
||___|| ||__|| ||__|| __|| Copyright (c) 1994-2005
||---|| ___|| World Wide Web: http://haskell.org/hugs
|| || Bugs: http://hackage.haskell.org/trac/hugs
|| || Version: September 2006 _________________________________________
Hugs mode: Restart with command line option +98 for Haskell 98 mode
Type :? for help
Hugs> "hello: привет"
"hello: \1087\1088\1080\1074\1077\1090"
Hugs> 'Я'
'\1071'
Hugs> putStrLn "hello: привет"
hello: привет
Hugs> :q
[Leaving Hugs]
$ locale
LANG=ru_RU.UTF-8
LC_CTYPE="ru_RU.UTF-8"
LC_NUMERIC="ru_RU.UTF-8"
LC_TIME="ru_RU.UTF-8"
LC_COLLATE="ru_RU.UTF-8"
LC_MONETARY="ru_RU.UTF-8"
LC_MESSAGES="ru_RU.UTF-8"
LC_PAPER="ru_RU.UTF-8"
LC_NAME="ru_RU.UTF-8"
LC_ADDRESS="ru_RU.UTF-8"
LC_TELEPHONE="ru_RU.UTF-8"
LC_MEASUREMENT="ru_RU.UTF-8"
LC_IDENTIFICATION="ru_RU.UTF-8"
LC_ALL=
$
我们可以猜测这是因为 print
和 show
用于格式化结果,并且这些函数尽最大努力以规范、最大可移植的方式格式化数据——所以他们更喜欢转义奇怪的字符(也许是甚至在 Haskell 的标准中都有说明):
$ ghci
GHCi, version 7.0.1: http://www.haskell.org/ghc/ :? for help
Prelude> show 'Я'
"'\\1071'"
Prelude> :q
Leaving GHCi.
$ hugs -98
Type :? for help
Hugs> show 'Я'
"'\\1071'"
Hugs> :q
[Leaving Hugs]
$
但是,如果我们知道如何破解 GHCi 或 Hugs 以人类可读的方式打印这些字符,即直接,未转义,那就太好了。在将交互式 Haskell 环境用于教育目的时,您可以在非英语观众面前进行 Haskell 教程/演示,您希望在他们的人类语言中展示一些有关数据的 Haskell。
实际上,它不仅可用于教育目的,还可用于调试!当您有在表示其他语言单词的字符串上定义的函数时,使用非 ASCII 字符。因此,如果程序是特定于语言的,并且只有另一种语言的词作为数据才有意义,并且您的函数仅在这些词上定义,那么在 GHCi 中调试时查看这些数据很重要。
总结一下我的问题:有哪些方法可以破解现有的交互式 Haskell 环境,以便在结果中更友好地打印 Unicode? (在我的情况下,“更友好”意味着“更简单”:我希望 GHCi 或 Hugs 中的 print
以简单直接的方式显示非拉丁字符,如 putChar
、 putStrLn
所做的那样,即未转义。)
(也许,除了 GHCi 和 Hugs98 之外,我还会看看现有的 Emacs 与 Haskell 交互的模式,看看它们是否可以以漂亮的、未转义的方式呈现结果。)
破解此问题的一种方法是将 GHCi 包装到 shell 包装器中,该包装器读取其标准输出并取消转义 Unicode 字符。这当然不是 Haskell 的方式,但它可以完成工作:)
例如,这是一个使用 sh
和 python3
的包装器 ghci-esc
(这里 3 很重要):
#!/bin/sh
ghci "$@" | python3 -c '
import sys
import re
def tr(match):
s = match.group(1)
try:
return chr(int(s))
except ValueError:
return s
for line in sys.stdin:
sys.stdout.write(re.sub(r"\\([0-9]{4})", tr, line))
'
ghci-esc
的用法:
$ ./ghci-esc
GHCi, version 7.0.2: http://www.haskell.org/ghc/ :? for help
> "hello"
"hello"
> "привет"
"привет"
> 'Я'
'Я'
> show 'Я'
"'\Я'"
> :q
Leaving GHCi.
请注意,并非上述所有取消转义都正确完成,但这是向观众展示 Unicode 输出的快速方法。
我是一名优秀的程序员,十分优秀!