計算機プログラムの構造と解釈 第二版(第二章)
- 作者: ハロルドエイブルソン,ジュリーサスマン,ジェラルド・ジェイサスマン,Harold Abelson,Julie Sussman,Gerald Jay Sussman,和田英一
- 出版社/メーカー: 翔泳社
- 発売日: 2014/05/17
- メディア: 大型本
- この商品を含むブログ (4件) を見る
Scheme でなく Ruby でやるのだ。
lispy.rb
class Cell def initialize(a, b) @car = a @cdr = b end attr_accessor :car, :cdr def inspect "(#{@car.inspect}, #{@cdr.inspect})" end alias :to_s :inspect end class Array def list iter = ->(a, b) { if a.empty? b else iter[a[0...-1], Cell.new(a[-1], b)] end } iter[slice(0...-1), Cell.new(slice(-1), nil)] end alias :~ :list end Cons = ->(a, b) {Cell.new(a, b)} List = ->(ar) {ar.list} Car = ->(ar) {ar.car} Cdr = ->(ar) {ar.cdr} if __FILE__ == $0 p List[[1, 2, 3]] #=>(1, (2, (3, nil))) p ~[:a, :b, :c] #=>(:a, (:b, (:c, nil))) p Cons[Cons[1, 2], Cons[3, 4]] #=>((1, 2), (3, 4)) p Cons[Cons[1, Cons[2, 3]], 4] #=>((1, (2, 3)), 4) end
有理数の実装。
require_relative 'lispy' make_rat = ->(n, d) {Cons[n, d]} numer = ->(x) {Car[x]} denom = ->(x) {Cdr[x]} p_rat = ->(x) {puts "#{numer[x]}/#{denom[x]}"} gcd = ->(a, b) { b.zero? ? a : gcd[b, a % b] } make_rat = ->(n, d) { g = gcd[n, d] n1, d1 = n / g, d / g n1, d1 = -n1, -d1 if d1 < 0 Cons[n1, d1] } add_rat = ->(x, y) { make_rat[numer[x] * denom[y] + numer[y] * denom[x], denom[x] * denom[y]] } sub_rat = ->(x, y) { make_rat[numer[x] * denom[y] - numer[y] * denom[x], denom[x] * denom[y]] } mul_rat = ->(x, y) { make_rat[numer[x] * numer[y], denom[x] * denom[y]] } div_rat = ->(x, y) { make_rat[numer[x] * denom[y], denom[x] * numer[y]] } is_equal_rat = ->(x, y) { numer[x] * denom[y] == numer[y] * denom[x] } one_half = make_rat[1, 2] p_rat[one_half] #=>1/2 one_third = make_rat[1, 3] p_rat[add_rat[one_half, one_third]] #=>5/6 p_rat[mul_rat[one_half, one_third]] #=>1/6 p_rat[div_rat[one_half, one_third]] #=>3/2 p is_equal_rat[one_half, one_half] #=>true
問題2.2。
make_point = ->(a, b) {Cons[a, b]} x_point = ->(point) {Car[point]} y_point = ->(point) {Cdr[point]} p_point = ->(point) {puts "(#{x_point[point]}, #{y_point[point]})"} make_segment = ->(start_po, end_po) {Cons[start_po, end_po]} start_segment = ->(segment) {Car[segment]} end_segment = ->(segment) {Cdr[segment]} midpoint_segment = ->(seg) { s, e = start_segment[seg], end_segment[seg] make_point[(x_point[s] + x_point[e]) / 2, (y_point[s] + y_point[e]) / 2] } p1 = make_point[1, 2] p2 = make_point[7, 12] seg = make_segment[p1, p2] p_point[midpoint_segment[seg]] #=>(4, 7)
問題2.3。
make_rectangle = ->(a, b) { a, b = b, a if x_point[a] > x_point[b] Cons[a, b] } width = ->(rect) {x_point[Cdr[rect]] - x_point[Car[rect]]} height = ->(rect) {(y_point[Cdr[rect]] - y_point[Car[rect]]).abs} perimeter = ->(rect) {(width[rect] + height[rect]) * 2} area = ->(rect) {width[rect] * height[rect]} p rect1 = make_rectangle[p2, p1] #=>((1, 2), (7, 12)) p perimeter[rect1] #=>32 p area[rect1] #=>60
データとは何か
cons = ->(x, y) { dispatch = ->(m) { if m.zero? x elsif m == 1 y else raise "Argument not 0 or 1 -- CONS #{m}" end } } car = ->(z) {z[0]} cdr = ->(z) {z[1]} p car[cons[2, 3]] #=>2 p cdr[cons[2, 3]] #=>3
問題2.4。これはややこしい。
cons = ->(x, y) {->(m) {m[x, y]}} car = ->(z) {z[->(p, q) {p}]} cdr = ->(z) {z[->(p, q) {q}]} p car[cons[2, 3]] #=>2 p cdr[cons[2, 3]] #=>3
問題2.5。
cons = ->(a, b) {2 ** a * 3 ** b} count = ->(x, a) { iter = ->(i, n) { (i % a != 0) ? n : iter[i / a, n + 1] } iter[x, 0] } car = ->(z) {count[z, 2]} cdr = ->(z) {count[z, 3]} p car[cons[2, 3]] #=>2 p cdr[cons[2, 3]] #=>3