考虑以下示例(λ>
= ghci,$
= shell):
λ> writeFile "d" $ show "d"
$ cat d
"d"
λ> writeFile "d" "d"
$ cat d
d
λ> writeFile "backslash" $ show "\\"
$ cat backslash
"\\"
λ> writeFile "backslash" "\\"
$ cat backslash
\
λ> writeFile "cat" $ show "" -- U+1F408
$ cat cat
"\128008"
λ> writeFile "cat" ""
$ cat cat
我理解"\128008"
的另一种方式只是另一种表达方式
Haskell源代码中的""
。
我的问题是:为什么""
示例的行为类似于反斜杠而不是
像"d"
?因为它是一个可打印的角色,所以不应该表现得像
一封信?
更一般地说,确定角色是否适用的规则是什么 显示为可打印字符还是转义码?我看了Section 6.3 在Haskell 2010语言报告中,但它没有指定确切的行为。
答案 0 :(得分:6)
show
n作为图形字符。*其他所有内容都将被转义。*除了双引号(因为它们用于字符串分隔符)和 反斜杠(因为它们是逃逸所必需的)。
让我们看看源代码来解决这个问题!
由于我们有String = [Char]
,我们应该寻找instance Show Char
来源。它可以找到
here。
它被定义为:
-- | @since 2.01
instance Show Char where
showsPrec _ '\'' = showString "'\\''"
showsPrec _ c = showChar '\'' . showLitChar c . showChar '\''
showList cs = showChar '"' . showLitString cs . showChar '"'
因此显示String
(使用showList
)基本上是一个包装器
ShowLitString
,并显示Char
是ShowLitChar
的包装。
让我们来看看这些功能。
showLitString :: String -> ShowS
-- | Same as 'showLitChar', but for strings
-- It converts the string to a string using Haskell escape conventions
-- for non-printable characters. Does not add double-quotes around the
-- whole thing; the caller should do that.
-- The main difference from showLitChar (apart from the fact that the
-- argument is a string not a list) is that we must escape double-quotes
showLitString [] s = s
showLitString ('"' : cs) s = showString "\\\"" (showLitString cs s)
showLitString (c : cs) s = showLitChar c (showLitString cs s)
-- [explanatory comments ...]
正如您所期望的那样,showLitString
主要是一个包装器
showLitChar
。
[注意:如果您不熟悉ShowS
类型,这很好
answer了解原因
它可能有用。]
不是我们想要的,所以让我们去showLitChar
(我已经
省略了与问题无关的定义部分。
-- | Convert a character to a string using only printable characters,
-- using Haskell source-language escape conventions. For example:
-- [...]
showLitChar :: Char -> ShowS
showLitChar c s | c > '\DEL' = showChar '\\' (protectEsc isDec (shows (ord c)) s)
-- ^ Pattern matched for cat
showLitChar '\DEL' s = showString "\\DEL" s
showLitChar '\\' s = showString "\\\\" s
-- ^ Pattern matched for backslash
showLitChar c s | c >= ' ' = showChar c s
-- ^ Pattern matched for d
-- Some more escape codes
showLitChar '\a' s = showString "\\a" s
-- similarly for '\b', '\f', '\n', '\r', '\t', '\v' etc.
-- showLitChar ... = ...
现在你看到问题所在。 ord c
是int
,第一个是ord '\DEL' == 127
对于所有非ASCII字符(-- | @since 2.01
instance Show Char where
)。
对于ASCII范围内的字符,将打印可打印字符
其余的都逃脱了。对于外面的字符,所有字符都被转义。
代码没有回答问题的“原因”部分。答案就是这样 (我认为)是我们看到的第一条评论:
git blame
如果我猜测,这种行为一直存在以保持倒退
兼容性。我不需要猜测:请参阅评论以获得一些好的答案。
我们可以使用GHC的Github镜像在线进行Data.Char
;)。让我们来看看
这段代码写的时候
(blame link)。
相关的commit是15岁(!)。但是,确实提到了Unicode。
区分不同类型Unicode字符的功能
存在于isPrint c = iswprint (ord c) /= 0
foreign import ccall unsafe "u_iswprint"
iswprint :: Int -> Int
模块中。查看source:
iswprint
如果你跟踪引入void *exec_threads(void* arg){
int *counter = (int*)arg;
int index = mult/threads * (*counter);
SortedListElement_t* element = (SortedList_t*)malloc(sizeof(SortedList_t));
for(int i = 0; i < iterations; i++){
element->key = &keys[index + i];
SortedList_insert(list, element);
}
for(int i = 0; i < iterations; i++){
element = SortedList_lookup(list, &keys[index + i]);
if(element == NULL){
fprintf(stderr, "Could not find element %c in the list\n", keys[index+i]);
exit(2);
}
if(SortedList_delete(element)){
fprintf(stderr, "Corrupted list\n");
exit(2);
}
}
free(arg);
return NULL;
的提交,你就会登陆
here。这项承诺是在13年前作出的。
也许这两年他们没有写出足够的代码
想打破?我不知道。如果一些GHC开发人员可以更多地了解这一点,
在评论中,Daniel Wagner和Paul Johnson指出了一个很好的理由 - 使用非Unicode系统进行操作必须是一个高优先级(大约15年前),因为它非常棒。当时Unicode是相对较新的。