function add(x, y) { return apply_generic("add", list(x, y)); }
function sub(x, y) { return apply_generic("sub", list(x, y)); }
function mul(x, y) { return apply_generic("mul", list(x, y)); }
function div(x, y) { return apply_generic("div", list(x, y)); }
function install_javascript_number_package() {
function tag(x) {
return attach_tag("javascript_number", x);
}
put("add", list("javascript_number", "javascript_number"),
(x, y) => tag(x + y));
put("sub", list("javascript_number", "javascript_number"),
(x, y) => tag(x - y));
put("mul", list("javascript_number", "javascript_number"),
(x, y) => tag(x * y));
put("div", list("javascript_number", "javascript_number"),
(x, y) => tag(x / y));
put("make", "javascript_number",
x => tag(x));
return "done";
}
function make_javascript_number(n) {
return get("make", "javascript_number")(n);
}
function install_rational_package() {
// internal functions
function numer(x) { return head(x); }
function denom(x) { return tail(x); }
function make_rat(n, d) {
const g = gcd(n, d);
return pair(n / g, d / g);
}
function add_rat(x, y) {
return make_rat(numer(x) * denom(y) + numer(y) * denom(x),
denom(x) * denom(y));
}
function sub_rat(x, y) {
return make_rat(numer(x) * denom(y) - numer(y) * denom(x),
denom(x) * denom(y));
}
function mul_rat(x, y) {
return make_rat(numer(x) * numer(y),
denom(x) * denom(y));
}
function div_rat(x, y) {
return make_rat(numer(x) * denom(y),
denom(x) * numer(y));
}
// interface to rest of the system
function tag(x) {
return attach_tag("rational", x);
}
put("add", list("rational", "rational"),
(x, y) => tag(add_rat(x, y)));
put("sub", list("rational", "rational"),
(x, y) => tag(sub_rat(x, y)));
put("mul", list("rational", "rational"),
(x, y) => tag(mul_rat(x, y)));
put("div", list("rational", "rational"),
(x, y) => tag(div_rat(x, y)));
put("make", "rational",
(n, d) => tag(make_rat(n, d)));
return "done";
}
function make_rational(n, d) {
return get("make", "rational")(n, d);
}
function install_complex_package() {
// imported functions from rectangular and polar packages
function make_from_real_imag(x, y) {
return get("make_from_real_imag", "rectangular")(x, y);
}
function make_from_mag_ang(r, a) {
return get("make_from_mag_ang", "polar")(r, a);
}
// internal functions
function add_complex(z1, z2) {
return make_from_real_imag(real_part(z1) + real_part(z2),
imag_part(z1) + imag_part(z2));
}
function sub_complex(z1, z2) {
return make_from_real_imag(real_part(z1) - real_part(z2),
imag_part(z1) - imag_part(z2));
}
function mul_complex(z1, z2) {
return make_from_mag_ang(magnitude(z1) * magnitude(z2),
angle(z1) + angle(z2));
}
function div_complex(z1, z2) {
return make_from_mag_ang(magnitude(z1) / magnitude(z2),
angle(z1) - angle(z2));
}
// interface to rest of the system
function tag(z) { return attach_tag("complex", z); }
put("add", list("complex", "complex"),
(z1, z2) => tag(add_complex(z1, z2)));
put("sub", list("complex", "complex"),
(z1, z2) => tag(sub_complex(z1, z2)));
put("mul", list("complex", "complex"),
(z1, z2) => tag(mul_complex(z1, z2)));
put("div", list("complex", "complex"),
(z1, z2) => tag(div_complex(z1, z2)));
put("make_from_real_imag", "complex",
(x, y) => tag(make_from_real_imag(x, y)));
put("make_from_mag_ang", "complex",
(r, a) => tag(make_from_mag_ang(r, a)));
return "done";
}
function make_complex_from_real_imag(x, y){
return get("make_from_real_imag", "complex")(x, y);
}
function make_complex_from_mag_ang(r, a){
return get("make_from_mag_ang", "complex")(r, a);
}
downward,the outer tag that is used to direct it to the appropriate package is stripped off (by applying contents) and the next level of tag (if any) becomes visible to be used for further dispatching.
The problem is that the complex-number selectors were never defined for "complex" numbers, just for "polar" and "rectangular" numbers. All you have to do to make this work is add the following to the complex package:
put("real_part", list("complex"), real_part);
put("imag_part", list("complex"), imag_part);
put("magnitude", list("complex"), magnitude);
put("angle", list("complex"), angle);
magnitude(z);
apply_generic("magnitude", list(z));
// In this case:
// type_tags = map(type_tag, list(z))
// Which evaluates to:
// type_tags = list("complex");
// and
// fun = get("magnitude", list("complex"));
// which, due to the addition of
// put("magnitude", list("complex"), magnitude);
// fun = magnitude;
apply(magnitude, map(contents, list(z)));
apply(magnitude, pair("rectangular", pair(3, 4)));
magnitude(pair("rectangular"), pair(3, 4));
apply_generic("magnitude", list(pair("rectangular"), pair(3, 4)));
// type_tags = map(type_tag, list(z)) evaluates to list("rectangular")
// fun = get("magnitude", list("rectangular")) which evaluates to
// z => math_sqrt(square(real_part(z)) + square(imag_part(z)))
// z => math_sqrt(square(head(z)) + square(tail(z)))
apply(fun, map(contents, list(pair("rectangular"), pair(3, 4))))
apply(fun, pair(3, 4))
(z => math_sqrt(square(head(z)) + square(tail(z))))(pair(3, 4));
math_sqrt(square(head(pair(3, 4))) + square(tail(pair(3, 4))))
...
math_sqrt(square(3) + square(4));
...
math_sqrt(9 + 16);
math_sqrt(25);
5function attach_tag(type_tag, contents) {
return is_number(contents)
? pair("javascript_number", contents)
: pair(type_tag, contents);
}
function type_tag(datum) {
return is_number(datum)
? "javascript_number"
: is_pair(datum)
? head(datum)
: error(datum, "bad tagged datum -- type_tag");
}
function contents(datum) {
return is_number(datum)
? datum
: is_pair(datum)
? tail(datum)
: error(datum, "bad tagged datum -- contents");
}
// provided by GitHub user clean99
function is_equal(x, y) {
return apply_generic("is_equal", list(x, y));
}
function install_javascript_number_package() {
// ...
put("is_equal", list("javascript_number", "javascript_number"),
(x, y) => x === y);
// ...
}
function install_rational_package() {
// ...
function is_equal(x, y) {
return numer(x) * denom(y) === numer(y) * denom(x);
}
put("is_equal", list("rational", "rational"), is_equal);
// ...
}
function install_complex_package() {
// ...
function is_equal(z1, z2) {
return real_part(z1) === real_part(z2)
? imag_part(z1) === imag_part(z2)
: false;
}
put("is_equal", list("complex", "complex"),
is_equal);
//...
}
// provided by GitHub user clean99
function is_equal_to_zero(x) {
return apply_generic("is_equal_to_zero", list(x));
}
function install_javascript_number_package() {
// ...
put("is_equal_to_zero", "javascript_number",
x => x === 0);
// ...
}
function install_rational_package() {
// ...
function is_equal_to_zero(x) {
return numer(x) === 0;
}
put("is_equal_to_zero", "rational",
is_equal_to_zero);
// ...
}
function install_complex_package() {
// ...
function is_equal_to_zero(z) {
return real_part(z) === 0
? imag_part(z) === 0
: false;
}
put("is_equal_to_zero", "complex",
is_equal_to_zero);
//...
}