(sicp35)m3.1 ~ m3.5

やる気がでないので、3章を先に始める。

;;m3.1
(use srfi-1)
(define (make-accumulator sum)
  (lambda (n)
    (set! sum (+ sum n))
    sum))

(define A (make-accumulator 5))
;;適用する回数によって値が変わる。
(map (lambda (x) (A 10)) (iota 10))
;;	gosh> (15 25 35 45 55 65 75 85 95 105)

;;m3.2
(define (make-monitored f)
  (let ((n 0))
    (lambda (mf)
      (if (eq? 'how-many-calls? mf)
          n
          (begin
            (set! n (+ n 1))
            (f mf))))))
(define s (make-monitored sqrt))
(for-each (lambda (x) (s 100)) (iota 10))
(s 'how-many-calls?) ;;	gosh> 10


;;m3.3
(define (make-account balance pass)
  (define (withdraw amount)
    (if (>= balance amount)
        (begin (set! balance (- balance amount))
               balance)
        "Insufficient funds"))
  (define (deposit amount)
    (set! balance (+ balance amount))
    balance)
  (define (dispatch p m)
    (if (eq? p pass)
        (cond ((eq? m 'withdraw) withdraw)
              ((eq? m 'deposit) deposit)
              (else (error "Unknown request -- MAKE-ACOUNT" m)))
        (lambda (x) "Incorrect pasword!")))
  dispatch)
(define acc (make-account 100 'secret-password))
((acc 'some 'deposite) 50) ;;gosh> "Incorrect pasword!"
((acc 'secret-password 'deposit) 50)  ;;gosh> 150


;;m3.4
(define (make-account balance pass)
  (let ((c 7))
    (define (withdraw amount)
      (if (>= balance amount)
          (begin (set! balance (- balance amount))
                 balance)
          "Insufficient funds"))
    (define (deposit amount)
      (set! balance (+ balance amount))
      balance)
    (define (call-the-cops x)    "call-the-cops")
    (define (dispatch p m)
      (if (eq? p pass)
          (begin (set! c 7)
                 (cond ((eq? m 'withdraw) withdraw)
                       ((eq? m 'deposit) deposit)
                       (else (error "Unknown request -- MAKE-ACOUNT" m))))
          (begin (if (= c 0)
                     call-the-cops
                     (begin (set! c (- c 1))
                            (lambda (x) "Incorrect pasword!"))))))
    dispatch))
(define acc (make-account 100 'pass))
((acc 'pass 'deposit) 19)
(define (f a pass word)
  (map (lambda (x) ((a pass word) 10)) (iota 10)))
(f acc 'pass 'deposit )
;;	gosh> (110 120 130 140 150 160 170 180 190 200)
(f acc 'wrong 'deposit)
;;	gosh> (#0="Incorrect pasword!" #0# #0# #0# #0# #0# #0# #1="call-the-cops" #1# #1#)
;; #0#は Incorrect password! とメモリを共有している部分の表示。


(define rand
  ;; (let ((x random-init))
;;     (lambda ()
;;       (set! x (random-update x))
;;       x)))
  (lambda () (sys-random)))

(define (estimate-pi trials)
  (sqrt (/ 6 (monte-carlo trials cesaro-test))))
 
(define (monte-carlo trials experiment)
  (define (iter trials-remaining trials-passed)
    (cond ((= trials-remaining 0)
              (/ trials-passed trials))
           ((experiment)
            (iter (- trials-remaining 1) (+ trials-passed 1)))
           (else
            (iter (- trials-remaining 1) trials-passed))))
  (iter trials 0))

;;(monte-carlo 10 (lambda () #t))

;;m3.5

;;random-in-range が使えない。
;;てきとーに代用品をつくろう。

;; (define (f n)
;;   (let ((lst (map (lambda (x) (sys-random)) (iota n))))
;;     (apply max lst)))
;; (use srfi-1)
;; (apply max (map (lambda (x) (f 100000)) (iota 10)))

(define (random-in-range low high)
  (let ((range (- high low))
        (max 2147480021)) ;;sys-randomを何回かやった内の最大値
    (+ low (* range (/ (sys-random) max)))))
;; (map (lambda (x) (random-in-range 1.0 1.5)) (iota 20))

(define (estimate-integral p x1 x2 y1 y2 times)
  (define area (* (- x1 x2) (- y1 y2)))
  (define (iter c n)
    (if (= n 0)
        (* area (/ c times))
        (let ((x (random-in-range x2 x1))
              (y (random-in-range y2 y1)))
          (cond ((p x y)
                 (iter (+ c 1) (- n 1)))
                (else
                 (iter c (- n 1)))))))
  (iter 0 times))


;;あー、 monte-carlo を使った方がいいかも。忘れてた。



(define (estimate-integral p x1 x2 y1 y2 n)
  (define (experiment)
    (let ((x (random-in-range x2 x1))
          (y (random-in-range y2 y1)))
      (p x y)))
  (let ((area (* (- x1 x2) (- y1 y2))))
    (* area (monte-carlo n experiment))))


(define (square x) (* x x))

(define (m3-5 coord r n)
  ;;coord = (x . y)
  (let* ((x (car coord)) (y (cdr  coord))
         (min-x (- x r)) (max-x (+ x r))
         (min-y (- y r)) (max-y (+ y r)))
;;     (print "x(min . max) " min-x " .. "  max-x)
;;     (print "y(min . max) " min-y " .. "  max-y)
    (estimate-integral
     (lambda (u v)
       (> r (sqrt (+ (square (- u x)) (square (- v y))))))
                       max-x min-x max-y min-y n)))


(map (lambda (x) (m3-5 (cons 0 0) 1.0 10000)) (iota 5))
;;	gosh> (3.1688 3.1296 3.1468 3.146 3.18)