File: part16.lhs

package info (click to toggle)
haskell98-tutorial 200006-3
  • links: PTS
  • area: main
  • in suites: sarge
  • size: 624 kB
  • ctags: 11
  • sloc: haskell: 2,125; makefile: 80; sh: 13
file content (128 lines) | stat: -rw-r--r-- 4,352 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
Gentle Introduction to Haskell 98, Online Supplement 
Part 16
Covers Section 8, 8.1, 8.2, 8.3

> module Part16() where

Section: 8.1  Equality and Ordered Classes
Section: 8.2  Enumeration and Index Classes

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.

Section: 8.3   The Read and Show Classes

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.

> 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.

> 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. 

> 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 ('<' :).

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.

> 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.

> 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.

> 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.

> 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.

> 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 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"

Continued in part17.lhs