Section: 8.1 Equality and Ordered Classes
Section: 8.2 Enumeration and Index Classes
第 8.1 节 相等类与顺序类
第 8.2 节 枚举类与索引类
No examples are provided for 5.1 or 5.2. The standard Prelude contains many instance declarations which illustrate the Eq, Ord, and Enum classes.
5.1 和 5.2 没有提供例子。标准 Prelude 中包含大量实例声明,可以
展示 Eq、Ord 和 Enum 类。
Section: 8.3 The Read and Show Classes
第 8.3 节 Read 类与 Show 类
This is the slow showTree. The show function is part of the Text class and works with all the built-in types. The context Text a arises from the call to show for leaf values.
这是效率较低的 showTree。show 函数是 Text 类的一部分,适用于所有
内建类型。上下文 Text a 来自对叶子值调用 show 的需求。(注:原文
Text 应为 Show 之误。)
data Tree a = Leaf a | Branch (Tree a) (Tree a) deriving Show
showTree :: (Show a) => Tree a -> String
showTree (Leaf x) = show x
showTree (Branch l r) = "<" ++ showTree l ++ "|" ++ showTree r ++ ">"
tree1 :: Tree Int
tree1 = Branch (Leaf 1) (Branch (Leaf 3) (Leaf 6))
e1 = showTree tree1
Now the improved showTree; shows is already defined for all built in types.
现在是改进版的 showTree;shows 已经为所有内建类型定义了。
showsTree :: Show a => Tree a -> String -> String
showsTree (Leaf x) s = shows x s
showsTree (Branch l r) s = '<' : showsTree l ('|' : showsTree r ('>' : s))
e2 = showsTree tree1 ""
The final polished version. ShowS is predefined in the Prelude so we don't need it here.
最终打磨过的版本。ShowS 在 Prelude 中已预定义,所以这里不需要
再定义它。
showsTree' :: Show a => Tree a -> ShowS
showsTree' (Leaf x) = shows x
showsTree' (Branch l r) = ('<' :) . showsTree' l . ('|' :) .
showsTree' r . ('>' :)
e3 = showsTree' tree1 ""
In the Prelude, there is a showChar function that can be used instead of ('<' :).
在 Prelude 中有一个 showChar 函数,可以代替 ('<' :) 使用。
Now for the reading function. Again, ReadS is predefined and reads works for all built-in types. The generators in the list comprehensions are patterns: p <- l binds pattern p to successive elements of l which match p. Elements not matching p are skipped.
下面是读取函数。同样,ReadS 已预定义,reads 适用于所有内建类型。
列表推导中的生成器可以是模式:p <- l 把模式 p 绑定到 l 中依次与 p
匹配的元素上。不匹配 p 的元素会被跳过。
readsTree :: (Read a) => ReadS (Tree a)
readsTree ('<':s) = [(Branch l r, u) | (l, '|':t) <- readsTree s,
(r, '>':u) <- readsTree t ]
readsTree s = [(Leaf x,t) | (x,t) <- reads s]
e4 :: [(Int,String)]
e4 = reads "5 golden rings"
e5 :: [(Tree Int,String)]
e5 = readsTree "<1|<2|3>>"
e6 :: [(Tree Int,String)]
e6 = readsTree "<1|2"
e7 :: [(Tree Int,String)]
e7 = readsTree "<1|<<2|3>|<4|5>>> junk at end"
Before we do the next readTree, let's play with the lex function.
在做下一个 readTree 之前,先来玩玩 lex 函数。
e8 :: [(String,String)]
e8 = lex "foo bar bletch"
Here's a function to completely lex a string. This does not handle lexical ambiguity - lex would return more than one possible lexeme when an ambiguity is encountered and the patterns used here would not match.
这里是一个把字符串完全词法化的函数。它不处理词法歧义——遇到歧义时
lex 会返回多个可能的词位(lexeme),而这里使用的模式将无法匹配。
lexAll :: String -> [String]
lexAll s = case lex s of
[("",_)] -> [] -- lex returns an empty token if none is found
[(token,rest)] -> token : lexAll rest
e9 = lexAll "lexAll :: String -> [String]"
e10 = lexAll "<1|<a|3>>"
Finally, the complete reader. This is not sensitive to white space as were the previous versions. When you derive the Show class for a data type the reader generated automatically is similar to this in style.
最后是完整的读取器。它不像前面的版本那样对空白敏感。当你为数据类型
派生 Show 类时,自动生成的读取器在风格上也与这个类似。
readsTree' :: (Read a) => ReadS (Tree a)
readsTree' s = [(Branch l r, x) | ("<", t) <- lex s,
(l, u) <- readsTree' t,
("|", v) <- lex u,
(r, w) <- readsTree' v,
(">", x) <- lex w ]
++
[(Leaf x, t) | (x, t) <- reads s]
When testing this program, you must make sure the input conforms to Haskell lexical syntax. If you remove spaces between | and < or > they will lex as a single token as you should have noticed with e10.
测试这个程序时,必须确保输入符合 Haskell 的词法语法。如果你去掉
| 与 < 或 > 之间的空格,它们会被词化为一个单独的记号——你在 e10
中应该已经注意到了。
e11 :: [(Tree Int,String)]
e11 = readsTree' "<1 | <2 | 3> >"
e12 :: [(Tree Bool,String)]
e12 = readsTree' "<True|False>"
Finally, here is a simple version of read for trees only:
最后,这里是一个只针对树的简化版 read:
read' :: (Read a) => String -> (Tree a)
read' s = case (readsTree' s) of
[(tree,"")] -> tree -- Only one parse, no junk at end
[] -> error "Couldn't parse tree"
[_] -> error "Crud after the tree" -- unread chars at end
_ -> error "Ambiguous parse of tree"
e13 :: Tree Int
e13 = read' "foo"
e14 :: Tree Int
e14 = read' "< 1 | < 2 | 3 > >"
e15 :: Tree Int
e15 = read' "3 xxx"