我正在编写一个parsec解析器,它读入字符串并转换转义字符,作为练习3 here的一部分。
对于该练习,我正在使用此功能:
escapedCharFromChar :: Char -> Char
escapedCharFromChar c = read $ concat ["'\\",[c],"'"]
使用read
将字符x
转换为名为x
的转义字符时,我不会感到印象深刻。任何人都可以建议使用类型Char -> Char
更优雅的功能吗?
答案 0 :(得分:6)
read
(或更确切地说,Text.Read.Lex.lexCharE
)是GHC's internal table的结果,定义为:{/ p>
lexEscChar =
do c <- get
case c of
'a' -> return '\a'
'b' -> return '\b'
'f' -> return '\f'
'n' -> return '\n'
'r' -> return '\r'
't' -> return '\t'
'v' -> return '\v'
'\\' -> return '\\'
'\"' -> return '\"'
'\'' -> return '\''
_ -> pfail
最终,您必须在某处定义语义。您可以在程序中执行此操作,也可以重用GHC。
答案 1 :(得分:5)
一种方法是详尽地列出案例:
charFromEscape :: Char -> Char
charFromEscape 'n' = '\n'
charFromEscape 't' = '\t'
--- ... --- Help!
您也可以使用lookup
:
-- this import goes at the top of your source file
import Data.Maybe (fromJust)
charFromEscape :: Char -> Char
charFromEscape c = fromJust $ lookup c escapes
where escapes = [('n', '\n'), ('t', '\t')] -- and so on
fromJust
位可能看起来很奇怪。 lookup
的类型是
lookup :: (Eq a) => a -> [(a, b)] -> Maybe b
这意味着对于定义了相等性的某种类型的值和查找表,它希望从查找表中提供相应的值 - 但不保证您的密钥存在于表中!这就是Maybe
的目的,其定义是
data Maybe a = Just a | Nothing
使用fromJust
,假设您Just something
(即,c
在escapes
中有一个条目),但这会分崩离析当该假设无效时:
ghci> charFromEscape 'r' *** Exception: Maybe.fromJust: Nothing
这些示例将引导您进行练习,但很明显您希望更好地处理错误。此外,如果您希望查找表很大,您可能需要查看Data.Map。
答案 2 :(得分:1)
我只是使用模式匹配来处理我关心的少数逃逸 - 即't' -> '\t'
等。其他读者建议的解决方案类似。不是很通用,但很直接。