44 lines
1.7 KiB
Plaintext
44 lines
1.7 KiB
Plaintext
|
Chapter 5, challenge 1:
|
||
|
Earlier, I said that the | , * , and + forms we added to our grammar metasyntax
|
||
|
were just syntactic sugar. Take this grammar:
|
||
|
|
||
|
expr → expr ( "(" ( expr ( "," expr )* )? ")" | "." IDENTIFIER )+
|
||
|
| IDENTIFIER
|
||
|
| NUMBER
|
||
|
|
||
|
Produce a grammar that matches the same language but does not use any of the notational sugar.
|
||
|
|
||
|
solution:
|
||
|
expr -> IDENTIFIER
|
||
|
expr -> NUMBER
|
||
|
expr -> expr callOrIndex
|
||
|
|
||
|
callOrIndex -> "." IDENTIFIER
|
||
|
callOrIndex -> "(" call ")"
|
||
|
|
||
|
call ->
|
||
|
call -> expr
|
||
|
call -> expr callListEnd
|
||
|
|
||
|
callListEnd ->
|
||
|
callListEnd -> "," expr precedingCommaCall
|
||
|
|
||
|
|
||
|
The grammar here clearly describes a number, or an identifier to a number, or a
|
||
|
function call, or a structure access
|
||
|
|
||
|
Chapter 5, challenge 2:
|
||
|
The Visitor pattern lets you emulate the functional style in an object-oriented
|
||
|
language. Devise a complementary pattern for a functional language. It should let
|
||
|
you bundle all of the operations on one type together and let you define new types
|
||
|
easily.
|
||
|
(SML or Haskell would be ideal for this exercise, but Scheme or another Lisp works
|
||
|
as well.)
|
||
|
|
||
|
solution:
|
||
|
Here, we're supposed to be able to define a new type that "inherits" an
|
||
|
existing one and bundle all the function implementations on that type together.
|
||
|
We could simply write the functions by specific type in one place, since Haskell is just that flexible, but that doesn't guarrantee we wrote the needed functions.
|
||
|
Another thing we could do is to put all necessary functions in a single structure, and define a type for this structure, for example if our supertype is Expr, with functions like "printInStr", "execute" and "optimize", our function bundle would look like:
|
||
|
data ExprFuncs a = ExprFuncs (a -> str) (a -> IO ()) (a -> Expr)
|