SlideShare una empresa de Scribd logo
1 de 28
Descargar para leer sin conexión
Write Your Own Lisp in Clojure
Learn Lisp by making a Lisp
1
An Interpreter
2
Demo
3
Meta-circular evaluator
4
Eval
5
Apply
(defn form-apply [proc args]
(letfn [(primitive? [p] (= (first p) 'primitive))
(procedure? [p] (= (first p) 'procedure)) ;<-- from lambda
(proc-params [p] (second p))
(proc-body [p] (nth p 2))
(proc-env [p] (nth p 3))]
(cond (primitive? proc) (apply (second proc) args) ;<-- magic
(procedure? proc) (eval-seq (proc-body proc)
(extend-env (proc-env proc)
(proc-params proc)
args)))))
6
Primitive expressions
true, 123, "words" nil
var, my-fn
(defn form-eval [exp env]
(cond (self-evaluating? exp) exp
(symbol? exp) (env-get exp env)
(defn self-evaluating? [x]
(or (number? x)
(string? x)
(nil? x)
(boolean? x)))
7
Enviroment
8
Enviroment
(defn env-find [var env action not-found] ...)
(defn env-get [var env] ...)
(defn env-set [var val env] ...)
(defn extend-env [env] ...)
9
Initial Enviroment
(defn setup-env []
(-> '()
(extend-env (keys primitive-procs)
(map #(list 'primitive %) (vals primitive-procs)))
(extend-env)
(built-in!)
(extend-env)))
(def primitive-procs {'true true
'+ +
'car first
...})
primitive-procs
10
quote
(quote 1) => 1
(quote a) => a
(quote (+ 1 1)) => (+ 1 1)
(defn form-eval [exp env]
(cond (self-evaluating? exp) exp
(symbol? exp) (env-get exp env)
(= (first exp) 'quote) (second exp)) ;;<- here
11
if
(if <cond-expr> expr else-expr)
(defn form-eval [exp env]
(let [exp (macroexpand exp env)]
(cond (self-evaluating? exp) exp
(symbol? exp) (env-get exp env)
(= (first exp) 'quote) (second exp)
(= (first exp) 'if) (eval-if exp env)))) ; <- here
(defn eval-if [exp env]
(let [[a0 a1 a2 a3] exp]
(if (form-eval a1 env)
(form-eval a2 env)
(form-eval a3 env))))
12
Why is "if" a special form?
Can we just write a if function?
(defn iif [condition stat else]
(if (true? condition)
expr
else-expr))
(iif true (+ 1 2) (* 0 0)) ;=> 3
(iif false (+ 1 2) (* 0 0)) ;=> 0
(iif true (+ 1 2) (/ 0 0)) ;=> Error: ArithmeticException Divide by zero
13
begin
(begin expr1 expr2 ...)
like "do" in clojure
(defn form-eval [exp env]
(cond (self-evaluating? exp) exp
(symbol? exp) (env-get exp env)
(= (first exp) 'quote) (second exp)
(= (first exp) 'if) (eval-if exp env)
(= (first exp) 'begin) (eval-seq (rest exp) env))) ; <-- here
(defn eval-seq [exp env]
(reduce #(form-eval %2 env) nil exp))
14
lambda
(lambda (x y) (+ x y))
(lambda () 5)
(defn form-eval [exp env]
(cond (self-evaluating? exp) exp
; ...
(= (first exp) 'lambda) (eval-lambda exp env)))) ;<- here
(defn eval-lambda [exp env]
(list 'procedure ;<-- this is for form-apply
(second exp)
(drop 2 exp)
env))
15
define
(define x 1)
(define (f x y) (+ x y))
(define f (lambda (x y) (+ x y)))
(defn form-eval [exp env]
(let [exp (macroexpand exp env)]
(cond (self-evaluating? exp) exp
; ...
(= (first exp) 'define) (eval-define exp env)))) ;<-- here
16
eval-define
(defn define-var [exp]
(if (seq? (second exp)) ;function?
(first (second exp)) ;it's a function so the var is function name
(second exp)))
(defn define-val [exp env]
(let [var (second exp)
make-lambda #(cons 'lambda (cons %1 %2))]
(if (seq? var) ;function?
(form-eval (make-lambda (rest var) (drop 2 exp)) env)
(form-eval (nth exp 2) env))))
(defn eval-define [exp env]
(let [var (define-var exp)
val (define-val exp env)]
(swap! (first env) assoc var val))) 17
set!
(define x 5)
(set! x 10)
(defn form-eval [exp env]
(cond (self-evaluating? exp) exp
;...
(= (first exp) 'set!) (eval-assignment exp env))) ;<-- here
(defn eval-assignment [exp env]
(let [[op var val] exp]
(env-set var val env)))
18
let*
(let* ((var val) ...) body)
(defn form-eval [exp env]
(cond (self-evaluating? exp) exp
;...
(= (first exp) 'let*) (eval-let* exp env))) ;<--here
(defn eval-let* [exp env]
(let [eenv (extend-env env)
[op vars body] exp]
(doseq [[b e] vars]
(swap! (first eenv) assoc b (form-eval e eenv)))
(form-eval body eenv)))
19
defmacro
(defmacro binding (lambda (args) body))
(defn form-eval [exp env]
(cond (self-evaluating? exp) exp
;...
(= (first exp) 'defmacro) (eval-defmacro exp env))); <-here
(defn eval-defmacro [exp env]
(let [[a0 a1 a2] exp
mbody (with-meta (form-eval a2 env) {:ismacro true})]
(swap! (first env) assoc a1 mbody)
"ok"))
20
macroexpand
(defn form-eval [exp env]
(let [exp (macroexpand exp env)] ;<--here
(cond (self-evaluating? exp) exp
(= (first exp) 'macroexpand) (macroexpand (second exp) env)))) ;<-- here
(defn macroexpand [exp env]
(loop [exp exp]
(if (is-macro-call exp env)
(let [mac (env-get (first exp) env)]
(recur (form-apply mac (rest exp))))
exp)))
21
macroexpand (cont.)
(defn is-macro-call [exp env]
(and (seq? exp)
(symbol? (first exp))
(env-find (first exp)
env
#(:ismacro (meta (get @% (first exp))))
#(identity false))))
22
apply else
(defn form-eval [exp env]
(let [exp (macroexpand exp env)]
(cond (self-evaluating? exp) exp
;...
:else (form-apply (form-eval (first exp) env) ;<-- here
(map #(form-eval % env) (rest exp)))))
23
apply
(defn form-apply [proc args]
(letfn [(primitive? [p] (= (first p) 'primitive))
(procedure? [p] (= (first p) 'procedure)) ;;<-- from lambda
(proc-params [p] (second p))
(proc-body [p] (nth p 2))
(proc-env [p] (nth p 3))]
(cond (primitive? proc) (apply (second proc) args) ;;<-- magic
(procedure? proc) (eval-seq (proc-body proc)
(extend-env (proc-env proc)
(proc-params proc)
args)))))
24
Now you can write your own Lisp
in Clojure
25
Try it
(def env (setup-env))
(form-eval
'(define (fact x)
(if (eq? x 1)
1
(* x (fact (- x 1))))) env) ;=> ok
(form-eval
'(fact 6) env)) ;=> 720
More examples
26
Still some thing
Add your built-in functions
REPL
27
Question?
28

Más contenido relacionado

La actualidad más candente

Jscex: Write Sexy JavaScript (中文)
Jscex: Write Sexy JavaScript (中文)Jscex: Write Sexy JavaScript (中文)
Jscex: Write Sexy JavaScript (中文)
jeffz
 
Reverse Engineering: C++ "for" operator
Reverse Engineering: C++ "for" operatorReverse Engineering: C++ "for" operator
Reverse Engineering: C++ "for" operator
erithion
 
Quinto Punto Parte B
Quinto Punto Parte BQuinto Punto Parte B
Quinto Punto Parte B
gustavo206
 

La actualidad más candente (20)

Unit test
Unit testUnit test
Unit test
 
The Ring programming language version 1.5.2 book - Part 75 of 181
The Ring programming language version 1.5.2 book - Part 75 of 181The Ring programming language version 1.5.2 book - Part 75 of 181
The Ring programming language version 1.5.2 book - Part 75 of 181
 
The Ring programming language version 1.10 book - Part 94 of 212
The Ring programming language version 1.10 book - Part 94 of 212The Ring programming language version 1.10 book - Part 94 of 212
The Ring programming language version 1.10 book - Part 94 of 212
 
Solving callback hell with good old function composition
Solving callback hell with good old function compositionSolving callback hell with good old function composition
Solving callback hell with good old function composition
 
Jscex: Write Sexy JavaScript (中文)
Jscex: Write Sexy JavaScript (中文)Jscex: Write Sexy JavaScript (中文)
Jscex: Write Sexy JavaScript (中文)
 
Reverse Engineering: C++ "for" operator
Reverse Engineering: C++ "for" operatorReverse Engineering: C++ "for" operator
Reverse Engineering: C++ "for" operator
 
Ecma script 5
Ecma script 5Ecma script 5
Ecma script 5
 
Hidden Gems of Ruby 1.9
Hidden Gems of Ruby 1.9Hidden Gems of Ruby 1.9
Hidden Gems of Ruby 1.9
 
The Ring programming language version 1.9 book - Part 91 of 210
The Ring programming language version 1.9 book - Part 91 of 210The Ring programming language version 1.9 book - Part 91 of 210
The Ring programming language version 1.9 book - Part 91 of 210
 
Google Guava
Google GuavaGoogle Guava
Google Guava
 
Коварный code type ITGM #9
Коварный code type ITGM #9Коварный code type ITGM #9
Коварный code type ITGM #9
 
CROCHET - Checkpoint Rollback in JVM (ECOOP 2018)
CROCHET - Checkpoint Rollback in JVM (ECOOP 2018)CROCHET - Checkpoint Rollback in JVM (ECOOP 2018)
CROCHET - Checkpoint Rollback in JVM (ECOOP 2018)
 
DataStructures notes
DataStructures notesDataStructures notes
DataStructures notes
 
2013-02-21 - .NET UG Rhein-Neckar: JavaScript Best Practices
2013-02-21 - .NET UG Rhein-Neckar: JavaScript Best Practices2013-02-21 - .NET UG Rhein-Neckar: JavaScript Best Practices
2013-02-21 - .NET UG Rhein-Neckar: JavaScript Best Practices
 
Pratt Parser in Python
Pratt Parser in PythonPratt Parser in Python
Pratt Parser in Python
 
Quinto Punto Parte B
Quinto Punto Parte BQuinto Punto Parte B
Quinto Punto Parte B
 
Functional programming with php7
Functional programming with php7Functional programming with php7
Functional programming with php7
 
Implementing virtual machines in go & c 2018 redux
Implementing virtual machines in go & c 2018 reduxImplementing virtual machines in go & c 2018 redux
Implementing virtual machines in go & c 2018 redux
 
PHP for Python Developers
PHP for Python DevelopersPHP for Python Developers
PHP for Python Developers
 
Fine-grained Processing of CVS Archives with APFEL
Fine-grained Processing of CVS Archives with APFELFine-grained Processing of CVS Archives with APFEL
Fine-grained Processing of CVS Archives with APFEL
 

Similar a Lisp

The Magnificent Seven
The Magnificent SevenThe Magnificent Seven
The Magnificent Seven
Mike Fogus
 
Feel of Kotlin (Berlin JUG 16 Apr 2015)
Feel of Kotlin (Berlin JUG 16 Apr 2015)Feel of Kotlin (Berlin JUG 16 Apr 2015)
Feel of Kotlin (Berlin JUG 16 Apr 2015)
intelliyole
 
深入浅出Jscex
深入浅出Jscex深入浅出Jscex
深入浅出Jscex
jeffz
 
Implement the following sorting algorithms Bubble Sort Insertion S.pdf
Implement the following sorting algorithms  Bubble Sort  Insertion S.pdfImplement the following sorting algorithms  Bubble Sort  Insertion S.pdf
Implement the following sorting algorithms Bubble Sort Insertion S.pdf
kesav24
 

Similar a Lisp (20)

The Magnificent Seven
The Magnificent SevenThe Magnificent Seven
The Magnificent Seven
 
Monadologie
MonadologieMonadologie
Monadologie
 
Next Level Testing
Next Level TestingNext Level Testing
Next Level Testing
 
Introduction To Lisp
Introduction To LispIntroduction To Lisp
Introduction To Lisp
 
CQL 实现
CQL 实现CQL 实现
CQL 实现
 
SDC - Einführung in Scala
SDC - Einführung in ScalaSDC - Einführung in Scala
SDC - Einführung in Scala
 
Feel of Kotlin (Berlin JUG 16 Apr 2015)
Feel of Kotlin (Berlin JUG 16 Apr 2015)Feel of Kotlin (Berlin JUG 16 Apr 2015)
Feel of Kotlin (Berlin JUG 16 Apr 2015)
 
Parametricity - #cljsyd - May, 2015
Parametricity - #cljsyd - May, 2015Parametricity - #cljsyd - May, 2015
Parametricity - #cljsyd - May, 2015
 
The Functional Programming Triad of Folding, Scanning and Iteration - a first...
The Functional Programming Triad of Folding, Scanning and Iteration - a first...The Functional Programming Triad of Folding, Scanning and Iteration - a first...
The Functional Programming Triad of Folding, Scanning and Iteration - a first...
 
Scala for Jedi
Scala for JediScala for Jedi
Scala for Jedi
 
Introduction to Scala
Introduction to ScalaIntroduction to Scala
Introduction to Scala
 
Pooya Khaloo Presentation on IWMC 2015
Pooya Khaloo Presentation on IWMC 2015Pooya Khaloo Presentation on IWMC 2015
Pooya Khaloo Presentation on IWMC 2015
 
A swift introduction to Swift
A swift introduction to SwiftA swift introduction to Swift
A swift introduction to Swift
 
深入浅出Jscex
深入浅出Jscex深入浅出Jscex
深入浅出Jscex
 
Programming in lua STRING AND ARRAY
Programming in lua STRING AND ARRAYProgramming in lua STRING AND ARRAY
Programming in lua STRING AND ARRAY
 
Groovy puzzlers по русски с Joker 2014
Groovy puzzlers по русски с Joker 2014Groovy puzzlers по русски с Joker 2014
Groovy puzzlers по русски с Joker 2014
 
Are we ready to Go?
Are we ready to Go?Are we ready to Go?
Are we ready to Go?
 
Implement the following sorting algorithms Bubble Sort Insertion S.pdf
Implement the following sorting algorithms  Bubble Sort  Insertion S.pdfImplement the following sorting algorithms  Bubble Sort  Insertion S.pdf
Implement the following sorting algorithms Bubble Sort Insertion S.pdf
 
Functional Programming with Groovy
Functional Programming with GroovyFunctional Programming with Groovy
Functional Programming with Groovy
 
Damn Fine CoffeeScript
Damn Fine CoffeeScriptDamn Fine CoffeeScript
Damn Fine CoffeeScript
 

Último

%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
masabamasaba
 
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdfintroduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
VishalKumarJha10
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service provider
mohitmore19
 

Último (20)

%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand
 
Generic or specific? Making sensible software design decisions
Generic or specific? Making sensible software design decisionsGeneric or specific? Making sensible software design decisions
Generic or specific? Making sensible software design decisions
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
 
VTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnVTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learn
 
%in Durban+277-882-255-28 abortion pills for sale in Durban
%in Durban+277-882-255-28 abortion pills for sale in Durban%in Durban+277-882-255-28 abortion pills for sale in Durban
%in Durban+277-882-255-28 abortion pills for sale in Durban
 
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
 
%+27788225528 love spells in Vancouver Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Vancouver Psychic Readings, Attraction spells,Br...%+27788225528 love spells in Vancouver Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Vancouver Psychic Readings, Attraction spells,Br...
 
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
 
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
 
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdfintroduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
 
SHRMPro HRMS Software Solutions Presentation
SHRMPro HRMS Software Solutions PresentationSHRMPro HRMS Software Solutions Presentation
SHRMPro HRMS Software Solutions Presentation
 
AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation Template
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Models
 
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
 
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
Direct Style Effect Systems -The Print[A] Example- A Comprehension AidDirect Style Effect Systems -The Print[A] Example- A Comprehension Aid
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
 
Architecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the pastArchitecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the past
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service provider
 
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
 
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) SolutionIntroducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
 

Lisp

  • 1. Write Your Own Lisp in Clojure Learn Lisp by making a Lisp 1
  • 6. Apply (defn form-apply [proc args] (letfn [(primitive? [p] (= (first p) 'primitive)) (procedure? [p] (= (first p) 'procedure)) ;<-- from lambda (proc-params [p] (second p)) (proc-body [p] (nth p 2)) (proc-env [p] (nth p 3))] (cond (primitive? proc) (apply (second proc) args) ;<-- magic (procedure? proc) (eval-seq (proc-body proc) (extend-env (proc-env proc) (proc-params proc) args))))) 6
  • 7. Primitive expressions true, 123, "words" nil var, my-fn (defn form-eval [exp env] (cond (self-evaluating? exp) exp (symbol? exp) (env-get exp env) (defn self-evaluating? [x] (or (number? x) (string? x) (nil? x) (boolean? x))) 7
  • 9. Enviroment (defn env-find [var env action not-found] ...) (defn env-get [var env] ...) (defn env-set [var val env] ...) (defn extend-env [env] ...) 9
  • 10. Initial Enviroment (defn setup-env [] (-> '() (extend-env (keys primitive-procs) (map #(list 'primitive %) (vals primitive-procs))) (extend-env) (built-in!) (extend-env))) (def primitive-procs {'true true '+ + 'car first ...}) primitive-procs 10
  • 11. quote (quote 1) => 1 (quote a) => a (quote (+ 1 1)) => (+ 1 1) (defn form-eval [exp env] (cond (self-evaluating? exp) exp (symbol? exp) (env-get exp env) (= (first exp) 'quote) (second exp)) ;;<- here 11
  • 12. if (if <cond-expr> expr else-expr) (defn form-eval [exp env] (let [exp (macroexpand exp env)] (cond (self-evaluating? exp) exp (symbol? exp) (env-get exp env) (= (first exp) 'quote) (second exp) (= (first exp) 'if) (eval-if exp env)))) ; <- here (defn eval-if [exp env] (let [[a0 a1 a2 a3] exp] (if (form-eval a1 env) (form-eval a2 env) (form-eval a3 env)))) 12
  • 13. Why is "if" a special form? Can we just write a if function? (defn iif [condition stat else] (if (true? condition) expr else-expr)) (iif true (+ 1 2) (* 0 0)) ;=> 3 (iif false (+ 1 2) (* 0 0)) ;=> 0 (iif true (+ 1 2) (/ 0 0)) ;=> Error: ArithmeticException Divide by zero 13
  • 14. begin (begin expr1 expr2 ...) like "do" in clojure (defn form-eval [exp env] (cond (self-evaluating? exp) exp (symbol? exp) (env-get exp env) (= (first exp) 'quote) (second exp) (= (first exp) 'if) (eval-if exp env) (= (first exp) 'begin) (eval-seq (rest exp) env))) ; <-- here (defn eval-seq [exp env] (reduce #(form-eval %2 env) nil exp)) 14
  • 15. lambda (lambda (x y) (+ x y)) (lambda () 5) (defn form-eval [exp env] (cond (self-evaluating? exp) exp ; ... (= (first exp) 'lambda) (eval-lambda exp env)))) ;<- here (defn eval-lambda [exp env] (list 'procedure ;<-- this is for form-apply (second exp) (drop 2 exp) env)) 15
  • 16. define (define x 1) (define (f x y) (+ x y)) (define f (lambda (x y) (+ x y))) (defn form-eval [exp env] (let [exp (macroexpand exp env)] (cond (self-evaluating? exp) exp ; ... (= (first exp) 'define) (eval-define exp env)))) ;<-- here 16
  • 17. eval-define (defn define-var [exp] (if (seq? (second exp)) ;function? (first (second exp)) ;it's a function so the var is function name (second exp))) (defn define-val [exp env] (let [var (second exp) make-lambda #(cons 'lambda (cons %1 %2))] (if (seq? var) ;function? (form-eval (make-lambda (rest var) (drop 2 exp)) env) (form-eval (nth exp 2) env)))) (defn eval-define [exp env] (let [var (define-var exp) val (define-val exp env)] (swap! (first env) assoc var val))) 17
  • 18. set! (define x 5) (set! x 10) (defn form-eval [exp env] (cond (self-evaluating? exp) exp ;... (= (first exp) 'set!) (eval-assignment exp env))) ;<-- here (defn eval-assignment [exp env] (let [[op var val] exp] (env-set var val env))) 18
  • 19. let* (let* ((var val) ...) body) (defn form-eval [exp env] (cond (self-evaluating? exp) exp ;... (= (first exp) 'let*) (eval-let* exp env))) ;<--here (defn eval-let* [exp env] (let [eenv (extend-env env) [op vars body] exp] (doseq [[b e] vars] (swap! (first eenv) assoc b (form-eval e eenv))) (form-eval body eenv))) 19
  • 20. defmacro (defmacro binding (lambda (args) body)) (defn form-eval [exp env] (cond (self-evaluating? exp) exp ;... (= (first exp) 'defmacro) (eval-defmacro exp env))); <-here (defn eval-defmacro [exp env] (let [[a0 a1 a2] exp mbody (with-meta (form-eval a2 env) {:ismacro true})] (swap! (first env) assoc a1 mbody) "ok")) 20
  • 21. macroexpand (defn form-eval [exp env] (let [exp (macroexpand exp env)] ;<--here (cond (self-evaluating? exp) exp (= (first exp) 'macroexpand) (macroexpand (second exp) env)))) ;<-- here (defn macroexpand [exp env] (loop [exp exp] (if (is-macro-call exp env) (let [mac (env-get (first exp) env)] (recur (form-apply mac (rest exp)))) exp))) 21
  • 22. macroexpand (cont.) (defn is-macro-call [exp env] (and (seq? exp) (symbol? (first exp)) (env-find (first exp) env #(:ismacro (meta (get @% (first exp)))) #(identity false)))) 22
  • 23. apply else (defn form-eval [exp env] (let [exp (macroexpand exp env)] (cond (self-evaluating? exp) exp ;... :else (form-apply (form-eval (first exp) env) ;<-- here (map #(form-eval % env) (rest exp))))) 23
  • 24. apply (defn form-apply [proc args] (letfn [(primitive? [p] (= (first p) 'primitive)) (procedure? [p] (= (first p) 'procedure)) ;;<-- from lambda (proc-params [p] (second p)) (proc-body [p] (nth p 2)) (proc-env [p] (nth p 3))] (cond (primitive? proc) (apply (second proc) args) ;;<-- magic (procedure? proc) (eval-seq (proc-body proc) (extend-env (proc-env proc) (proc-params proc) args))))) 24
  • 25. Now you can write your own Lisp in Clojure 25
  • 26. Try it (def env (setup-env)) (form-eval '(define (fact x) (if (eq? x 1) 1 (* x (fact (- x 1))))) env) ;=> ok (form-eval '(fact 6) env)) ;=> 720 More examples 26
  • 27. Still some thing Add your built-in functions REPL 27