牌語備忘録 -pygo

あくまでもメモです。なるべくオフィシャルの情報を参照してください。

牌語備忘録 -pygo

2.4.2 Tagged dataをPythonでやってみた

SICP2.4.2 Tagged dataあたりをPythonでやってみた

scheme(original code)

;2.4.2  Tagged data
(define (attach-tag type-tag contents)
  (cons type-tag contents))
(define (type-tag datum)
  (if (pair? datum)
      (car datum)
      (error "Bad tagged datum -- TYPE-TAG" datum)))
(define (contents datum)
  (if (pair? datum)
      (cdr datum)
      (error "Bad tagged datum -- CONTENTS" datum)))

(define (rectangular? z)
  (eq? (type-tag z) 'rectangular))
(define (polar? z)
  (eq? (type-tag z) 'polar))

(define (real-part-rectangular z) (car z))
(define (imag-part-rectangular z) (cdr z))
(define (magnitude-rectangular z)
  (sqrt (+ (square (real-part-rectangular z))
           (square (imag-part-rectangular z)))))
(define (angle-rectangular z)
  (atan (imag-part-rectangular z)
        (real-part-rectangular z)))
(define (make-from-real-imag-rectangular x y)
  (attach-tag 'rectangular (cons x y)))
(define (make-from-mag-ang-rectangular r a) 
  (attach-tag 'rectangular
              (cons (* r (cos a)) (* r (sin a)))))

(define (real-part-polar z)
  (* (magnitude-polar z) (cos (angle-polar z))))
(define (imag-part-polar z)
  (* (magnitude-polar z) (sin (angle-polar z))))
(define (magnitude-polar z) (car z))
(define (angle-polar z) (cdr z))
(define (make-from-real-imag-polar x y) 
  (attach-tag 'polar
               (cons (sqrt (+ (square x) (square y)))
                     (atan y x))))
(define (make-from-mag-ang-polar r a)
  (attach-tag 'polar (cons r a)))

(define (real-part z)
  (cond ((rectangular? z) 
         (real-part-rectangular (contents z)))
        ((polar? z)
         (real-part-polar (contents z)))
        (else (error "Unknown type -- REAL-PART" z))))
(define (imag-part z)
  (cond ((rectangular? z)
         (imag-part-rectangular (contents z)))
        ((polar? z)
         (imag-part-polar (contents z)))
        (else (error "Unknown type -- IMAG-PART" z))))
(define (magnitude z)
  (cond ((rectangular? z)
         (magnitude-rectangular (contents z)))
        ((polar? z)
         (magnitude-polar (contents z)))
        (else (error "Unknown type -- MAGNITUDE" z))))
(define (angle z)
  (cond ((rectangular? z)
         (angle-rectangular (contents z)))
        ((polar? z)
         (angle-polar (contents z)))
        (else (error "Unknown type -- ANGLE" z))))

(define (add-complex z1 z2)
  (make-from-real-imag (+ (real-part z1) (real-part z2))
                       (+ (imag-part z1) (imag-part z2))))

(define (make-from-real-imag x y)
  (make-from-real-imag-rectangular x y))
(define (make-from-mag-ang r a)
  (make-from-mag-ang-polar r a))

;test
(make-from-real-imag 1 2)
(make-from-mag-ang 3 4)
(add-complex (make-from-real-imag 1 2) (make-from-mag-ang 3 4))

結果

(rectangular 1 . 2)
(polar 3 . 4)
(rectangular -0.9609308625908359 . -0.27040748592378483)
python
#2.4.2  Tagged data
from __future__ import division
import math

def attach_tag(type_tag, contents):
    return [type_tag, contents]
def type_tag(datum):
    if len(datum) >= 2:
        return datum[0]
    print "error: Bad tagged datum -- TYPE-TAG", datum
def contents(datum):
    if len(datum) >= 2:
        return datum[1]
    print "error: Bad tagged datum -- CONTENTS", datum

    
def rectangular_q(z):
    return type_tag(z) == 'rectangular'
def polar_q(z):
    return type_tag(z) == 'polar'

def real_part_rectangular(z):
    return z[0]
def imag_part_rectangular(z):
    return z[1]
def magnitude_rectangular(z):
    return math.sqrt(real_part_rectangular(z) **2 + \
                         imag_part_rectangular(z) ** 2)
def angle_rectangular(z):
    return math.atan2(imag_part_rectangular(z), real_part_rectangular(z))
def make_from_real_imag_rectangular(x, y):
    return attach_tag('rectangular', [x, y])
def make_from_mag_ang_rectangular(r, a):
    return attach_tag('rectangular', [r * math.cons(a),
                                      r * math.sin(a)])
def real_part_polar(z):
    return magnitude_polar(z) * math.cos(angle_polar(z))
def imag_part_polar(z):
    return magnitude_polar(z) * math.sin(angle_polar(z))
def magnitude_polar(z):
    return z[0]
def angle_polar(z):
    return z[1]
def make_from_real_imag_polar(x, y):
    return attach_tag('polar', [math.sqrt(x **2 + y **2), math.atan2(y,x)])
def make_from_mag_ang_polar(r,a):
    return attach_tag('polar', [r, a])

def real_part(z):
    if rectangular_q(z):
        return real_part_rectangular(contents(z))
    if polar_q(z):
        return real_part_polar(contents(z))
    else:
        print "error: Unknown type -- REAL-PART", z
def imag_part(z):
    if rectangular_q(z):
        return imag_part_rectangular(contents(z))
    if polar_q(z):
        return imag_part_polar(contents(z))
    else:
        print "error: Unknown type -- IMAG-PART", z
def magnitude(z):
    if rectangular_q(z):
        return magnitude_rectangular(contents(z))
    if polar_q(z):
        return magnitude_polar(contents(z))
    else:
        print "error: Unknown type -- MAGNITUDE", z
def angle(z):
    if rectangular_q(z):
        return angle_rectangular(contents(z))
    if polar_q(z):
        return angle_polar(contents(z))
    else:
        print "error: Unknown type -- ANGLE", z

def add_complex(z1, z2):
    return make_from_real_imag(real_part(z1) + real_part(z2), \
                                   imag_part(z1) + imag_part(z2))

def make_from_real_imag(x, y):
    return make_from_real_imag_rectangular(x, y)
def make_from_mag_ang(r, a):
    return make_from_mag_ang_polar(r, a)

#test
ri = make_from_real_imag(1,2)
ma =  make_from_mag_ang(3,4)
print ri
print ma
print add_complex(ri, ma)

結果

['rectangular', [1, 2]]
['polar', [3, 4]]
['rectangular', [-0.96093086259083593, -0.27040748592378483]]