code.scm 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400
  1. ;; ============
  2. ;; INTRODUCTION
  3. ;; ============
  4. ;; This chapter deals with the writing of a simple interpreter for
  5. ;; S-expressions.
  6. ;; =============
  7. ;; PREREQUISITES
  8. ;; =============
  9. (define first car)
  10. (define second cadr)
  11. (define third caddr)
  12. (define build list)
  13. ;; ===============
  14. ;; CODE OF CHAPTER
  15. ;; ===============
  16. (define new-entry build)
  17. (define lookup-in-entry
  18. (lambda (name entry lookup-fallback-proc)
  19. (lookup-in-entry-helper name
  20. (first entry)
  21. (second entry)
  22. lookup-fallback-proc)))
  23. (define lookup-in-entry-helper
  24. (lambda (name keys values lookup-fallback-proc)
  25. (cond
  26. [(null? keys) (lookup-fallback-proc name)]
  27. [(eq? name (car keys)) (car values)]
  28. [else
  29. (lookup-in-entry-helper name
  30. (cdr keys)
  31. (cdr values)
  32. lookup-fallback-proc)])))
  33. (define extend-table cons)
  34. (define new-table
  35. (lambda (entry)
  36. (extend-table entry '())))
  37. (define lookup-in-table
  38. (lambda (name table lookup-failure-proc)
  39. (cond
  40. [(null? table) (lookup-failure-proc name)]
  41. [else
  42. (lookup-in-entry name
  43. (car table)
  44. ;; fallback will be to look up the name in the rest of
  45. ;; the table
  46. (lambda (name)
  47. (lookup-in-table name
  48. (cdr table)
  49. ;; the failure proc is retained, to be
  50. ;; called when there are no more
  51. ;; entries to continue the lookup in
  52. lookup-failure-proc)))])))
  53. ;; 6 types:
  54. ;; const
  55. ;; quote
  56. ;; identifier
  57. ;; lambda
  58. ;; cond
  59. ;; application
  60. ;; An action is a representation of a type (???).
  61. ;; An S-expression is either an atom or a list.
  62. ;; -> There are 2 cases to distinguish, when transforming an S-expression to an action.
  63. ;; Given code:
  64. (define expression-to-action
  65. (lambda (expr)
  66. (cond
  67. [(atom? expr)
  68. (atom-to-action expr)]
  69. [else
  70. (list-to-action expr)])))
  71. ;; =====
  72. ;; Task: Define `atom-to-action`.
  73. ;; =====
  74. (define atom-to-action
  75. (lambda (#|atom|# a)
  76. (cond
  77. [(number? a) *const]
  78. [(eq? a #t) *const]
  79. [(eq? a #f) *const]
  80. [(eq? a 'cons) *const]
  81. [(eq? a 'car) *const]
  82. [(eq? a 'cdr) *const]
  83. [(eq? a 'null?) *const]
  84. [(eq? a 'eq?) *const]
  85. [(eq? a 'atom?) *const]
  86. [(eq? a 'zero?) *const]
  87. [(eq? a 'add1) *const]
  88. [(eq? a 'sub1) *const]
  89. [(eq? a 'number?) *const]
  90. [else *identifier])))
  91. ;; =====
  92. ;; Task: Define `list-to-action`.
  93. ;; =====
  94. (define list-to-action
  95. (lambda (#|list|# l)
  96. (cond
  97. [(atom? (car l))
  98. (cond
  99. [(eq? (car l) 'quote) *quote]
  100. [(eq? (car l) 'lambda) *lambda]
  101. [(eq? (car l) 'cond) *cond]
  102. [else *application])]
  103. [else *application])))
  104. ;; Given code:
  105. (define value
  106. (lambda (expr)
  107. ;; Q: Why is there an empty list as an argument here?
  108. ;; A: This is an empty table! This means that the meaning of something is
  109. ;; the meaning it has in some table.
  110. (meaning expr '())))
  111. ;; The procedure `meaning` is only a tool for figuring out what action to take
  112. ;; next.
  113. (define meaning
  114. (lambda (expr table)
  115. ;; Apply the result of `expression-to-action` to the expression and a table.
  116. ;; Actions seem to be what calculates a result of an expression.
  117. ;; Those actions are not yet defined.
  118. ;; For example this could be:
  119. ;; ((expression-to-action '(cdr '(1 2 3))) '(cdr (x y z))
  120. ;; '(((x y z)
  121. ;; (1 2 3))))
  122. ;; ≡
  123. ;; (*application '(cdr (x y z))
  124. ;; '(((x y z)
  125. ;; (1 2 3))))
  126. ((expression-to-action expr) expr table)))
  127. ;; Thought: It is weird to name `meaning` `meaning`, if it calculates the result
  128. ;; of some expression, as "meaning" is not necessarily something itself.
  129. ;; Some "actions" do not really need the given table.
  130. (define *const
  131. (lambda (expr table)
  132. (cond
  133. [(number? expr) expr]
  134. [(eq? expr #t) #t]
  135. [(eq? expr #f) #f]
  136. [else
  137. (build 'primitive expr)])))
  138. (define *quote
  139. (lambda (expr table)
  140. (text-of expr)))
  141. ;; =====
  142. ;; Task: Define `text-of`.
  143. ;; =====
  144. (define text-of second)
  145. ;; Explanation: Something quoted has the form `(quote something)`, so the second
  146. ;; part is the quoted thing. But why name it its "text"?
  147. (define *identifier
  148. (lambda (expr table)
  149. ;; An identifier's meaning depends on the environment or table it is defined
  150. ;; in.
  151. (lookup-in-table expr
  152. table
  153. ;; Not sure why the lambda is named `initial-table`.
  154. ;; I was not sure what to put here.
  155. initial-table)))
  156. ;; The book gives a definition of `initial-table` then:
  157. ;; Given code:
  158. (define initial-table
  159. (lambda (name)
  160. (car '())))
  161. ;; Which will result in an error.
  162. ;; Given code:
  163. (define *lambda
  164. (lambda (the-lambda table)
  165. (build 'non-primitive
  166. (cons table
  167. ;; The cdr of a lambda expression is its argument list and a
  168. ;; body.
  169. (cdr the-lambda)))))
  170. #|
  171. (meaning (lambda (x) (cons x y))
  172. (((y z) ((8) 9))))
  173. is
  174. (*lambda (lambda (x) (cons x y))
  175. (((y z) ((8) 9))))
  176. is
  177. (build 'non-primitive
  178. ((((y z) ((8) 9)))
  179. (x)
  180. (cons x y)))
  181. |#
  182. ;; =====
  183. ;; Task: Write table-of, formals-of and body-of.
  184. ;; =====
  185. (define table-of first)
  186. (define formals-of second)
  187. (define body-of third)
  188. ;; Writing a function for evaluating a cond expression. This can be done,
  189. ;; because we now have code that evaluates code and thus is one level above the
  190. ;; evaluated code. This is why we do only need a normal function to evaluate a
  191. ;; cond expression. A macro is basically the same thing as such one level above
  192. ;; code, because it processes the code before it is run.
  193. ;; Also note, that cond is not an *application. As the book continues to
  194. ;; explain, in an *application expression, all the arguments must be evaluated,
  195. ;; before the application can be done.
  196. (define evaluate-cond-q-and-a-lines
  197. (lambda (q-and-a-lines table)
  198. ;; When evaluating a cond expression, we in turn rely on cond in our
  199. ;; one-level-above language. This cond is not necessarily the same as the
  200. ;; cond in the code we are processing.
  201. (cond
  202. ;; Check for an else-branch. In this case evaluate the answer part.
  203. [(else? (question-of (car q-and-a-lines)))
  204. (meaning (answer-of (car q-and-a-lines)))]
  205. ;; If there is a normal question, then it needs to be evaluated, to get its
  206. ;; boolean return value.
  207. [(meaning (question-of (car q-and-a-lines)))
  208. (meaning (answer-of (car q-and-a-lines)))]
  209. ;; Otherwise consider the next question answer pair.
  210. [else
  211. (evaluate-cond-q-and-a-lines (cdr q-and-a-lines) table)])))
  212. ;; =====
  213. ;; Task: Write `else?`, `question-of` and `answer-of`.
  214. ;; =====
  215. (define else?
  216. (lambda (something)
  217. ;; The book includes a check for `atom?`. I am not sure why this is
  218. ;; necessary, if we already check whether `something` is equal to the symbol
  219. ;; `else`.
  220. (eq? something 'else)))
  221. (define question-of first)
  222. (define answer-of second)
  223. ;; =====
  224. ;; Task: Write the *cond action.
  225. ;; =====
  226. (define *cond
  227. (lambda (cond-expr table)
  228. (evaluate-cond-q-and-a-lines (cond-q-and-a-lines-of cond-expr) table)))
  229. ;; not only `second`, as there is possibly a list of cond-q-and-a-lines.
  230. (define cond-q-and-a-lines-of cdr)
  231. ;; =====
  232. ;; Task: Write a function evaluate-list.
  233. ;; =====
  234. (define evaluate-list
  235. (lambda (list-expression table)
  236. (cond
  237. ;; If the list is empty, then the result is also empty.
  238. [(null? list-expression) '()]
  239. [else
  240. (cons (meaning (car list-expression) table)
  241. (evaluate-list (cdr list-expression) table))])))
  242. ;; This will "reduce" the list elements (arguments), so that they are ready to
  243. ;; have the function applied to them.
  244. (define *application
  245. (lambda (expr table)
  246. (apply
  247. ;; get the identifier or lambda-expression of the application
  248. (meaning (function-of expr) table)
  249. ;; get the arguments of the application
  250. (meaning (arguments-of expr) table))))
  251. ;; An input to *application could be:
  252. ;; (*application '(cdr (x y z))
  253. ;; '(((x y z)
  254. ;; (1 2 3))))
  255. ;; Which would be calculated as follows:
  256. ;; (*application '(cdr (x y z))
  257. ;; '(((x y z)
  258. ;; (1 2 3))))
  259. ;; ≡
  260. ;; (*application '(cdr (x y z))
  261. ;; '(((x y z)
  262. ;; (1 2 3))))
  263. ;; =====
  264. ;; Task: Write `function-of` and `arguments-of`.
  265. ;; =====
  266. (define function-of car)
  267. (define arguments-of cdr)
  268. ;; The book distinguishes between primitives and non-primitives as types of
  269. ;; functions, where primitives are the ones, which need to already be defined in
  270. ;; our language to construct non-primitives from them. The functions are marked
  271. ;; as primitives or non-primitives by putting a tag (a symbol) in an expression,
  272. ;; which represents a primitive or a non-primitive. It is tagged data.
  273. ;; We can see this being put in our implementation of *lambda and *const. In the
  274. ;; predicates `primitive?` and `non-primitive?` we look for those markers.
  275. (define primitive?
  276. (lambda (sth)
  277. (eq? (first sth) 'primitive)))
  278. (define non-primitive?
  279. (lambda (sth)
  280. (eq? (first sth) 'non-primitive)))
  281. ;; Now we define `apply` as follows:
  282. (define apply
  283. (lambda (func args)
  284. ;; Depending on whether a procedure is a primitive or a non-primitive, the
  285. ;; application happens in different ways.
  286. (cond
  287. [(primitive? func)
  288. ;; first of func is the tag for primitive or non-primitive.
  289. ;; '(primitive func-name args)
  290. (apply-primitive (second func) args)]
  291. [(non-primitive? func)
  292. (apply-closure (second func) args)])))
  293. ;; Q: But now how do we implement `apply-primitive` and `apply-closure`?!
  294. ;; A: The book gives the following definition with gaps to fill in:
  295. ;; =====
  296. ;; Task: Fill the gaps.
  297. ;; =====
  298. ;; Explanation: The whole time we were writing procedures to evaluate lists, which represent
  299. ;; programs. This `apply-primitive` procedure is all about understanding, what kind of expression we
  300. ;; have to evaluate and then do the transformation, which leads to the evaluation result on our
  301. ;; one-level-above language. For example, if we find a `car`, then we need to get the first element
  302. ;; of the list that is in `vals`. This is what we do in our one-level-above language. The result is
  303. ;; returned as a value, which is reinserted into the evaluated language's context.
  304. (define apply-primitive
  305. (lambda (name vals)
  306. (cond
  307. [(eq? name #| here was a gap |# cons)
  308. (cons (first vals) (second vals))]
  309. [(eq? name 'car)
  310. (car (first vals))]
  311. [(eq? name 'cdr)
  312. (#| here was a gap |# ... (first vals))]
  313. [(eq? name 'null?)
  314. (null? (first vals))]
  315. [(eq? name 'eq?)
  316. (#| here was a gap |# ... (first vals) #| here was a gap |# ...)]
  317. [(eq? name 'atom?)
  318. (#| here was a gap |# ... (first vals))]
  319. [(eq? name 'zero?)
  320. (zero? (first vals))]
  321. [(eq? name 'add1)
  322. (+ (first vals) 1)]
  323. [(eq? name 'sub1)
  324. (- (first vals) 1)]
  325. [(eq? name 'number?)
  326. (number? (first vals))])))