(sicp49)m4.8,m4.9
合っているか自信無いです><
4.8named-letを作る
(define (named-let->definition exp) ;(letを外した式をもらう。 (let ((name (car exp)) (arguments (cadr exp)) (body (caddr exp))) (let ((vars (map car arguments)) (exps (map cadr arguments))) (sequence->exp (list (list 'define (cons name vars) body) (cons name exps)))))) ;;named-let ;前回のlet->lambdaは上手く動いて無かったみたい。 (define (let->lambda exp) (if (symbol? (cadr exp)) ;letの次の値がsymbolならnamed-let (named-let->definition (cdr exp)) (let ((arguments (cadr exp)) (body (cddr exp))) (let ((vars (map car arguments)) (exps (map cadr arguments))) (cons (make-lambda vars body) exps))))) (let->lambda '(let ((a 2) (b 1)) (+ a b))) ;((lambda (a b) (+ a b)) 2 1) (let->lambda '(let fib-iter ((a 0) (b 1) (c 10)) (if (zero? c) a (fib-iter b (+ a b) (- c 1))))) #|(begin (define (fib-iter a b c) (if (zero? c) a (fib-iter b (+ a b) (- c 1)))) (fib-iter 0 1 10)) |#
4.9 do, while, untilを作成する。
while,until,doの順序で考えた。
;;例えばこのような感じに使う。 (let ((sum 0) (n 10)) (while (> n 0) (set! sum (+ sum n)) (set! n (- n 1))) sum) ;;上手く動くには、whileが終了したらsumだけになってほしい。 ;;whileの終了時にwhile以降の式(ここではsum)を呼べばいい。 ;; (define (f anything rest) ;; (if <終了条件> ;; rest ;; <継続の処理>))という感じになる必要がある。。 (define (eval-while exp env) (let ((first (car exp)) (rest (cdr exp))) (define (run-while exp) (let ((pred (cadr exp)) (body (caddr exp))) (make-if pred (make-begin (list body (list run-while exp))) rest))) (eval (run-while first) env))) ;until (define (eval-until exp env) (let ((first (car exp)) (rest (cdr exp))) (define (run-until exp) (let ((pred (cadr exp)) (body (caddr exp))) (make-if pred rest (make-begin (list body (list run-until exp))))) (eval (run-until first) env))) ;;do ;;知らないので調べる。 ;; http://www.shido.info/lisp/scheme7.html ;; (do binds (predicate value) body) の形 ;; ;;例 ;; (define (fact-do n) ;; (do ((n1 n (- n1 1)) (p n (* p (- n1 1)))) ((= n1 1) p))) ;; ;binds n1<-n (loopする度に n1<- n1-1) ;; p<-n (loopする度に p<- p * (n1-1) ;; ;predicate n1 = 1 ;; ;value(return value) p ;;こんな感じで使う? (define (total l) (do ((n 0 (+ n (car l))) (l l (cdr l))) ((null? l) n))) (define (make-let exp) (cons 'let exp) ;;こんな感じでいいのかな? (define (run-do exp) (let ((binding (cadr exp)) (predicate&value (caddr exp))) (let ((vars&exps (map (lambda (e) (list (car e) (cadr e))) binding)) (set-f (map caddr binding))) (make-let (list 'loop vars&exps (make-if (car predicate&value) (cadr predicate&value) (cons 'loop set-f))))))) (run-do '(do ((n 0 (+ n (car l))) (l l (cdr l))) ((null? l) n))) ;;gosh> (let loop ((n 0) (l l)) (if (null? l) n (loop (+ n (car l)) (cdr l)))) (define (eval-do exp env) (eval (run-do exp) env))
追記
whileとかuntilの中の関数の引数はいらないかも
; while (define (eval-while exp env) (let ((first (car exp)) (rest (cdr exp))) (let ((pred (cadr first)) (body (cddr first))) (define (run-while) (make-if pred (make-begin (list body (list run-while))) rest)) ;(run-while)))) (eval-sequence (run-while) env)))) ;;eval-sequenceの方ではなく、commentされているrun-whileの方の時の出力 (print (eval-while'((while (> n 10) (set! sum (+ sum n)) (set! n (+ n 1))) sum) 'env)) ;;(if (> n 10) (begin ((set! sum (+ sum n)) (set! n (+ n 1))) (#<closure (eval-while run-while)>)) (sum)) ;;最終的 (sum)が取り出されて、これをeval-sequenceに渡すとlast-sexp?がtrueになって、sumが出力されて終了。 ;until (define (eval-until exp env) (let ((first (car exp)) (rest (cdr exp))) (let ((pred (cadr first)) (body (caddr first))) (define (run-until) (make-if pred rest (make-begin (list body (list run-until))))) (eval-sequence (run-until) env)))