about summary refs log tree commit diff stats
path: root/js/games/nluqo.github.io/~bh/61a-pages/Lectures/2.4/trydata.scm
blob: f37c4a76da6ba40f595ff00aa9cf07775f7b67dd (plain) (blame)
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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
~cs60a/lectures/2.3/trydata.scm

 Conjugating verbs example...  notes for 29 Sept 1993

We could start with

(define (tps v); third person singular version of verb v
  (cond((equal? v 'eat) 'eats)  ; he eats
       ((equal? v 'drink) 'drinks)
       ((equal? v 'go)  'goes)
....
       (else (error "unknown verb"))))

We need a total of six programs. Maintaining this would be really terrible.


Let us take a really crude first approach with tables.
(These are sometimes referred to as properties... e.g.
put the 'fps property of the 'eat word to ....)
 We could do this:

(put 'eat 'fps 'eat)  ; I eat    (get 'eat 'fps) --> eat
(put 'eat 'sps 'eat)  ; You eat
(put 'eat 'tps 'eats) ; He eats  (get 'eat 'tps) -->  eats
(put 'eat 'fpp 'eat)  ; We eat
(put 'eat 'spp 'eat)  ; You eat
(put 'eat 'tps 'eat)  ; They eat

;;; etc for all other verbs.

then
(define (tps verb)  (get verb 'tps))
(define (sps verb)  (get verb 'sps)) ;etc. for 4 more

The advantage here is that we can add new verbs and not rewrite programs.

The problems:  this wastes a lot of table space and still not very robust.
(tps 'nonsense) --> ()  (no error message)

more robust six programs, each looking like this:

(define (tps verb)(let((answer (get verb 'tps)))
		    (if (not (null? answer)) answer
			(error 'tps "bad verb ~s~%" verb))))

Now, to reduce space consumption....

solution:  group verbs by type
                      "regular"  (just add -s in tps)  as eat, drink
                           -es       (just add -es in tps) as go, box
                      "irregular" (refer to list) be: (am are is are are are)

Then all we have to do is say that a verb is regular, and all its forms
are known.  We store most of the info on the TYPE not the data. Here's how:

(put 'eat 'verb-type 'regular)

(define (type-of-verb v) (get v 'verb-type))

(put 'fps 'regular root)  ; I eat, drink
(put 'sps 'regular root)  ; you eat, drink
(put 'tps 'regular (lambda(x)( add-s (root x))))  ; he eats, drinks
(put 'fpp 'regular root)  ; We eat, drink
etc.


Now we can write 

(define (tps verb) ;; third person singular
  (let ((proc (get (type-of-verb verb) 'tps)))

   ;; either proc is ()  i.e. not found  or we can
   ;; apply it to the root  verb:

    (if (not (null? proc)) (proc verb))
	(error 'tps "I don't know about verb ~s~% " verb))))

we need a total of six such programs..

...

How about using manifest types?  Earlier we had proposed (see data.scm)
that, instead of have the verb
be just 'eat, with a property  (get 'eat 'verb-type) -->  'regular

We talk about the verb as an abstraction with a type and a root,
and in the case of an irregular verb, contents that give specific
forms for the verb conjugation.  Although we cover it over with
abstraction: make-verb, type, root, contents  (see data.scm)  the verbs
look like this, if we print them as normal lisp:

'(regular . eat)   (that is, (cons 'regular  'eat))

and for an irregular verb we have '(irreg . (be am are is))
  {this actually prints as (irreg be am are is) }

where 
      (contents verb) is  (cdr verb) which is either (root) or (fp sp tp)

      (root (contents verb)) --> eat, drink etc.  (i.e. cdr)

      (type verb) is (car verb) --> regular, irregular, -es  (i.e. car)

Now with this abstraction, we have a similar program, but the
"type" program looks at the manifest type (car) rather than in a table.

(define (tps verb) ;; third person singular
  (let ((proc (get (type verb) 'tps)))  ;; this type = car gets manifest type

   ;; either proc is ()  i.e. not found  or we can
   ;; apply it to verb:

    (if (not (null? proc)) (proc verb))
	(error 'tps "I don't know about verb ~s~% " verb)))

for a total of 6 programs that are all about the same.. e.g.

(define (tpp verb) ;; third person singular
  (let ((proc (get (type verb) 'tpp)))
    (if (not (null? proc)) (proc verb))
	(error 'tpp "I don't know about verb ~s~% " verb)))

...........

Now, another simplification... Since fps, sps, tps, fpp, spp, tpp
are all almost the same program...

Why not do this: 

 (define (fps verb) (operate 'fps obj))
 (define (sps verb) (operate 'sps obj))
 (define (tps verb) (operate 'tps obj))
etc...

where operate is
(define (operate op obj)  ;; op is one of fps, sps, tps, fpp, spp, tpp
  (let ((proc (get (type obj) op)))
    (if (not (null? proc))
        (proc (contents obj))
        (error op "Undefined operator" (list op obj)))))

;;;;;;;;;;;;;;;;

;; some detailed notes on data.scm -- how lisp represents them

;; notes 

;; note that (cons 'a 'b)  is  (a . b)   but
;;           (cons 'a (cons 'b ())  is (a b)  ...

box -->  (es . box)
          ^     ^
    type- |     |-root

(get 'es 'fps) --> procedure   (actually, root)
(get 'es 'tps) --> procedure   (actually (lambda(x)(add-es (root x))))

(operate 'fps box) --> ((get (type box) 'fps) then apply it to "box" --> box
(operate 'tps box) --> ((get (type box) 'fps) then apply it to "box" --> boxes

(define be (make-irreg 'am 'are 'is))
be --> (irreg am are is)
          ^    ^  ^   \tps
    type- |    |  \sps
               |-fps