Advertisement
Guest User

Untitled

a guest
Nov 14th, 2019
153
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 13.68 KB | None | 0 0
  1. ;;; "Metacircular evaluator", basert på koden i seksjon 4.1.1-4.1.4 i SICP.
  2. ;;; Del av innlevering 3b i IN2040, høst 2019.
  3. ;;
  4. ;; Last hele filen inn i Scheme. For å starte read-eval-print loopen og
  5. ;; initialisere den globale omgivelsen, kjør:
  6. ;; (set! the-global-environment (setup-environment))
  7. ;; (read-eval-print-loop)
  8. ;;
  9. ;; Merk at det visse steder i koden, som i `special-form?', vanligvis
  10. ;; ville være mere naturlig å bruke `or' enn `cond'. Evaluatoren er
  11. ;; skrevet helt uten bruk av `and' / `or' for å vise at disse likevel
  12. ;; kan støttes i det implementerte språket selv om de ikke brukes i
  13. ;; implementeringsspråket. (Se oppgave 3a for mer om dette.)
  14.  
  15. ;; hack for å etterlikne SICPs feilmeldinger:
  16. (define exit-to-toplevel 'dummy)
  17. (call-with-current-continuation
  18. (lambda (cont) (set! exit-to-toplevel cont)))
  19.  
  20. (define (error reason . args)
  21. (display "ERROR: ")
  22. (display reason)
  23. (for-each (lambda (arg)
  24. (display " ")
  25. (write arg))
  26. args)
  27. (newline)
  28. (exit-to-toplevel))
  29.  
  30.  
  31. ;;; Selve kjernen i evaluatoren (seksjon 4.1.1, SICP):
  32. ;;; -----------------------------------------------------------------------
  33.  
  34. ;; Merk at vi skiller ut evaluering av special forms i en egen prosedyre.
  35.  
  36. (define (mc-eval exp env) ;; tilsvarer eval i SICP
  37. (cond ((self-evaluating? exp) exp)
  38. ((variable? exp) (lookup-variable-value exp env))
  39. ((special-form? exp) (eval-special-form exp env))
  40. ((application? exp)
  41. (mc-apply (mc-eval (operator exp) env)
  42. (list-of-values (operands exp) env)))
  43. (else
  44. (error "Unknown expression type -- mc-eval:" exp))))
  45.  
  46. (define (mc-apply proc args) ;; tilsvarer apply i SICP
  47. (cond ((primitive-procedure? proc)
  48. (apply-primitive-procedure proc args))
  49. ((compound-procedure? proc)
  50. (eval-sequence
  51. (procedure-body proc)
  52. (extend-environment
  53. (procedure-parameters proc)
  54. args
  55. (procedure-environment proc))))
  56. (else
  57. (error
  58. "Unknown procedure type -- mc-apply:" proc))))
  59.  
  60. (define (eval-special-form exp env)
  61. (cond ((quoted? exp) (text-of-quotation exp))
  62. ((assignment? exp) (eval-assignment exp env))
  63. ((definition? exp) (eval-definition exp env))
  64. ((if? exp) (eval-if exp env))
  65. ((lambda? exp)
  66. (make-procedure (lambda-parameters exp)
  67. (lambda-body exp)
  68. env))
  69. ((begin? exp)
  70. (eval-sequence (begin-actions exp) env))
  71. ((cond? exp) (mc-eval (cond->if exp) env))
  72. ;(3a)
  73. ((and? exp) (and-eval (cdr exp) env))
  74. ((or? exp) (or-eval (cdr exp) env))
  75. ))
  76.  
  77.  
  78. ;3a
  79. (define (and-eval exp env)
  80. (cond ((null? exp) #t)
  81. ((not (true? (caar exp))) #f)
  82. (else
  83. (and-eval (cdr exp) env))))
  84.  
  85. (define (or-eval exp env)
  86. (cond ((null? exp) #f)
  87. ((true? (caar exp)) #t)
  88. (else
  89. (or-eval (cdr exp) env))))
  90.  
  91. (define (true? exp)
  92. (cond (((lambda () exp)) #t)
  93. (else #f)))
  94.  
  95.  
  96.  
  97. (define (special-form? exp)
  98. (cond ((quoted? exp) #t)
  99. ((assignment? exp) #t)
  100. ((definition? exp) #t)
  101. ((if? exp) #t)
  102. ((lambda? exp) #t)
  103. ((begin? exp) #t)
  104. ((cond? exp) #t)
  105. ;(3a)
  106. ((and? exp) #t)
  107. ((or? exp) #t)
  108. (else #f)))
  109.  
  110. (define (list-of-values exps env)
  111. (if (no-operands? exps)
  112. '()
  113. (cons (mc-eval (first-operand exps) env)
  114. (list-of-values (rest-operands exps) env))))
  115.  
  116. (define (eval-if exp env)
  117. (if (true? (mc-eval (if-predicate exp) env))
  118. (mc-eval (if-consequent exp) env)
  119. (mc-eval (if-alternative exp) env)))
  120.  
  121. (define (eval-sequence exps env)
  122. (cond ((last-exp? exps) (mc-eval (first-exp exps) env))
  123. (else (mc-eval (first-exp exps) env)
  124. (eval-sequence (rest-exps exps) env))))
  125.  
  126. (define (eval-assignment exp env)
  127. (set-variable-value! (assignment-variable exp)
  128. (mc-eval (assignment-value exp) env)
  129. env)
  130. 'ok)
  131.  
  132. (define (eval-definition exp env)
  133. (define-variable! (definition-variable exp)
  134. (mc-eval (definition-value exp) env)
  135. env)
  136. 'ok)
  137.  
  138. ;;; Predikater + selektorer som definerer syntaksen til uttrykk i språket
  139. ;;; (seksjon 4.1.2, SICP)
  140. ;;; -----------------------------------------------------------------------
  141.  
  142. ;(3a)
  143. (define (and? exp) (tagged-list? exp 'and))
  144. (define (or? exp) (tagged-list? exp 'or))
  145.  
  146. (define (self-evaluating? exp)
  147. (cond ((number? exp) #t)
  148. ((string? exp) #t)
  149. ((boolean? exp) #t)
  150. (else #f)))
  151.  
  152. (define (tagged-list? exp tag)
  153. (if (pair? exp)
  154. (eq? (car exp) tag)
  155. #f))
  156.  
  157. (define (quoted? exp)
  158. (tagged-list? exp 'quote))
  159.  
  160. (define (text-of-quotation exp) (cadr exp))
  161.  
  162. (define (variable? exp) (symbol? exp))
  163.  
  164. (define (assignment? exp)
  165. (tagged-list? exp 'set!))
  166.  
  167. (define (assignment-variable exp) (cadr exp))
  168.  
  169. (define (assignment-value exp) (caddr exp))
  170.  
  171.  
  172. (define (definition? exp)
  173. (tagged-list? exp 'define))
  174.  
  175. (define (definition-variable exp)
  176. (if (symbol? (cadr exp))
  177. (cadr exp)
  178. (caadr exp)))
  179.  
  180. (define (definition-value exp)
  181. (if (symbol? (cadr exp))
  182. (caddr exp)
  183. (make-lambda (cdadr exp)
  184. (cddr exp))))
  185.  
  186.  
  187. (define (lambda? exp) (tagged-list? exp 'lambda))
  188.  
  189. (define (lambda-parameters exp) (cadr exp))
  190. (define (lambda-body exp) (cddr exp))
  191.  
  192. (define (make-lambda parameters body)
  193. (cons 'lambda (cons parameters body)))
  194.  
  195.  
  196. (define (if? exp) (tagged-list? exp 'if))
  197.  
  198. (define (if-predicate exp) (cadr exp))
  199.  
  200. (define (if-consequent exp) (caddr exp))
  201.  
  202. (define (if-alternative exp)
  203. (if (not (null? (cdddr exp)))
  204. (cadddr exp)
  205. 'false))
  206.  
  207. (define (make-if predicate consequent alternative)
  208. (list 'if predicate consequent alternative))
  209.  
  210.  
  211. (define (begin? exp) (tagged-list? exp 'begin))
  212.  
  213. (define (begin-actions exp) (cdr exp))
  214.  
  215. (define (last-exp? seq) (null? (cdr seq)))
  216. (define (first-exp seq) (car seq))
  217. (define (rest-exps seq) (cdr seq))
  218.  
  219. (define (sequence->exp seq)
  220. (cond ((null? seq) seq)
  221. ((last-exp? seq) (first-exp seq))
  222. (else (make-begin seq))))
  223.  
  224. (define (make-begin seq) (cons 'begin seq))
  225.  
  226.  
  227. (define (application? exp) (pair? exp))
  228. (define (operator exp) (car exp))
  229. (define (operands exp) (cdr exp))
  230.  
  231. (define (no-operands? ops) (null? ops))
  232. (define (first-operand ops) (car ops))
  233. (define (rest-operands ops) (cdr ops))
  234.  
  235.  
  236. (define (cond? exp) (tagged-list? exp 'cond))
  237.  
  238. (define (cond-clauses exp) (cdr exp))
  239.  
  240. (define (cond-else-clause? clause)
  241. (eq? (cond-predicate clause) 'else))
  242.  
  243. (define (cond-predicate clause) (car clause))
  244.  
  245. (define (cond-actions clause) (cdr clause))
  246.  
  247. (define (cond->if exp)
  248. (expand-clauses (cond-clauses exp)))
  249.  
  250. (define (expand-clauses clauses)
  251. (if (null? clauses)
  252. 'false ; no else clause
  253. (let ((first (car clauses))
  254. (rest (cdr clauses)))
  255. (if (cond-else-clause? first)
  256. (if (null? rest)
  257. (sequence->exp (cond-actions first))
  258. (error "ELSE clause isn't last -- COND->IF:"
  259. clauses))
  260. (make-if (cond-predicate first)
  261. (sequence->exp (cond-actions first))
  262. (expand-clauses rest))))))
  263.  
  264.  
  265. ;;; Evaluatorens interne datastrukturer for å representere omgivelser,
  266. ;;; prosedyrer, osv (seksjon 4.1.3, SICP):
  267. ;;; -----------------------------------------------------------------------
  268.  
  269. (define (false? x)
  270. (cond ((eq? x 'false) #t)
  271. ((eq? x #f) #t)
  272. (else #f)))
  273.  
  274. (define (true? x)
  275. (not (false? x)))
  276. ;; (som i SICP-Scheme'en vi tar med true/false som boolske verdier.)
  277.  
  278. (define (make-procedure parameters body env)
  279. (list 'procedure parameters body env))
  280.  
  281. (define (compound-procedure? p)
  282. (tagged-list? p 'procedure))
  283.  
  284.  
  285. (define (procedure-parameters p) (cadr p))
  286. (define (procedure-body p) (caddr p))
  287. (define (procedure-environment p) (cadddr p))
  288.  
  289.  
  290. (define (enclosing-environment env) (cdr env))
  291.  
  292. (define (first-frame env) (car env))
  293.  
  294. (define the-empty-environment '())
  295.  
  296. ;; En ramme er et par der car er variablene
  297. ;; og cdr er verdiene:
  298. (define (make-frame variables values)
  299. (cons variables values))
  300.  
  301. (define (frame-variables frame) (car frame))
  302. (define (frame-values frame) (cdr frame))
  303.  
  304. (define (add-binding-to-frame! var val frame)
  305. (set-car! frame (cons var (car frame)))
  306. (set-cdr! frame (cons val (cdr frame))))
  307.  
  308. (define (extend-environment vars vals base-env)
  309. (if (= (length vars) (length vals))
  310. (cons (make-frame vars vals) base-env)
  311. (if (< (length vars) (length vals))
  312. (error "Too many arguments supplied:" vars vals)
  313. (error "Too few arguments supplied:" vars vals))))
  314.  
  315. ;; Søker gjennom listene av variabel-bindinger i første ramme og
  316. ;; så bakover i den omsluttende omgivelsen. (Moro; to nivåer av
  317. ;; interne definisjoner med gjensidig rekursjon.)
  318. (define (lookup-variable-value var env)
  319. (define (env-loop env)
  320. (define (scan vars vals)
  321. ; parallell rekursjon på listene av symboler og verdier
  322. (cond ((null? vars)
  323. (env-loop (enclosing-environment env)))
  324. ((eq? var (car vars))
  325. (car vals))
  326. (else (scan (cdr vars) (cdr vals)))))
  327. (if (eq? env the-empty-environment)
  328. (error "Unbound variable:" var)
  329. (let ((frame (first-frame env)))
  330. (scan (frame-variables frame)
  331. (frame-values frame)))))
  332. (env-loop env))
  333.  
  334. ;; Endrer bindingen av 'var' til 'val' i en omgivelse
  335. ;; (gir feil dersom 'var' ikke er bundet):
  336. (define (set-variable-value! var val env)
  337. (define (env-loop env)
  338. (define (scan vars vals)
  339. (cond ((null? vars)
  340. (env-loop (enclosing-environment env)))
  341. ((eq? var (car vars))
  342. (set-car! vals val))
  343. (else (scan (cdr vars) (cdr vals)))))
  344. (if (eq? env the-empty-environment)
  345. (error "Unbound variable -- SET!:" var)
  346. (let ((frame (first-frame env)))
  347. (scan (frame-variables frame)
  348. (frame-values frame)))))
  349. (env-loop env))
  350.  
  351. ;; define-variable! legger til en ny binding mellom 'var' og 'val'
  352. ;; i den første rammen i omgivelsen 'env':
  353. (define (define-variable! var val env)
  354. (let ((frame (first-frame env)))
  355. (define (scan vars vals)
  356. (cond ((null? vars)
  357. (add-binding-to-frame! var val frame))
  358. ((eq? var (car vars))
  359. (set-car! vals val))
  360. (else (scan (cdr vars) (cdr vals)))))
  361. (scan (frame-variables frame)
  362. (frame-values frame))))
  363.  
  364.  
  365. ;;; Håndtering av primitiver og den globale omgivelsen (SICP seksjon 4.1.4)
  366. ;;; -----------------------------------------------------------------------
  367.  
  368. (define (setup-environment)
  369. (let ((initial-env
  370. (extend-environment (primitive-procedure-names)
  371. (primitive-procedure-objects)
  372. the-empty-environment)))
  373. (define-variable! 'true 'true initial-env)
  374. (define-variable! 'false 'false initial-env)
  375. (define-variable! 'nil '() initial-env)
  376. initial-env))
  377.  
  378. (define the-global-environment the-empty-environment)
  379. ;; For initialisering av den globale omgivelsen, se kommentar til slutt i fila.
  380.  
  381. (define (primitive-procedure? proc)
  382. (tagged-list? proc 'primitive))
  383.  
  384. (define (primitive-implementation proc) (cadr proc))
  385.  
  386. (define primitive-procedures
  387. (list (list 'car car)
  388. (list 'cdr cdr)
  389. (list 'cons cons)
  390. (list 'null? null?)
  391. (list 'not not)
  392. (list '+ +)
  393. (list '- -)
  394. (list '* *)
  395. (list '/ /)
  396. (list '= =)
  397. (list 'eq? eq?)
  398. (list 'equal? equal?)
  399. (list 'display
  400. (lambda (x) (display x) 'ok))
  401. (list 'newline
  402. (lambda () (newline) 'ok))
  403. ;;2a
  404. (list '1+
  405. (lambda (x) (+ 1 x)))
  406. (list '1-
  407. (lambda (x) (- 1 x)))
  408. ;; her kan vi legge til flere primitiver.
  409. ))
  410.  
  411. (define (primitive-procedure-names)
  412. (map car
  413. primitive-procedures))
  414.  
  415. (define (primitive-procedure-objects)
  416. (map (lambda (proc) (list 'primitive (cadr proc)))
  417. primitive-procedures))
  418.  
  419. (define apply-in-underlying-scheme apply)
  420.  
  421. (define (apply-primitive-procedure proc args)
  422. (apply-in-underlying-scheme
  423. (primitive-implementation proc) args))
  424.  
  425.  
  426. ;;; Hjelpeprosedyrer for REPL-interaksjon (SICP seksjon 4.1.4)
  427. ;;; -----------------------------------------------------------------------
  428.  
  429. (define input-prompt ";;; MC-Eval input:")
  430. (define output-prompt ";;; MC-Eval value:")
  431.  
  432. (define (read-eval-print-loop) ;;tilsvarer driver-loop i SICP
  433. (prompt-for-input input-prompt)
  434. (let ((input (read)))
  435. (let ((output (mc-eval input the-global-environment)))
  436. (announce-output output-prompt)
  437. (user-print output)))
  438. (read-eval-print-loop))
  439.  
  440. (define (prompt-for-input string)
  441. (newline) (newline) (display string) (newline))
  442.  
  443. (define (announce-output string)
  444. (newline) (display string) (newline))
  445.  
  446. (define (user-print object)
  447. (if (compound-procedure? object)
  448. (display (list 'compound-procedure
  449. (procedure-parameters object)
  450. (procedure-body object)
  451. '<procedure-env>))
  452. (display object)))
  453.  
  454. 'METACIRCULAR-EVALUATOR-LOADED
  455.  
  456. ;;; For å starte read-eval-print loopen og initialisere
  457. ;;; den globale omgivelsen, kjør:
  458. ;;; (set! the-global-environment (setup-environment))
  459. ;;; (read-eval-print-loop)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement