-
Notifications
You must be signed in to change notification settings - Fork 120
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Multiple syntax errors in solution to 2.58 #999
Comments
Noticed another problem, this time in the text: The example given for part 2 is:
The |
Apologies for the essay; this ended up being part debugging-notes, part solution explanation. The short version is that there were three problems:
For a final version that works, skip to the bottom. Problem 1We start off with SyntaxError. This is due to several unmatched parentheses. Here is the currently provided solution, with just the SyntaxErrors fixed (plus one added function is_variable(x) { return is_string(x); }
function is_same_variable(v1, v2) {
return is_variable(v1) && is_variable(v2) && v1 === v2;
}
function number_equal(exp, num) {
return is_number(exp) && exp === num;
}
function items_before_first(op, s) {
return head(s) === op
? null
: pair(head(s),
items_before_first(op, tail(s)));
}
function items_after_first(op, s) {
return head(s) === op
? tail(s)
: items_after_first(op, tail(s));
}
function make_sum(a1, a2) {
return number_equal(a1, 0)
? a2
: number_equal(a2, 0)
? a1
: is_number(a1) && is_number(a2)
? a1 + a2
: list(a1, "+", a2);
}
// a sequence of terms and operators is a sum
// if and only if at least one + operator occurs
function is_sum(x) {
return is_pair(x) &&
! is_null(member("+", x));
}
function addend(s) {
return items_before_first("+", s);
}
function augend(s) {
return items_after_first("+", s);
}
function make_product(m1, m2) {
return number_equal(m1, 0) || number_equal(m2, 0)
? 0
: number_equal(m1, 1)
? m2
: number_equal(m2, 1)
? m1
: is_number(m1) && is_number(m2)
? m1 * m2
: list(m1, "*", m2);
}
// a sequence of terms and operators is a product
// if and only if no + operator occurs
function is_product(x) {
return is_pair(x) && is_null(member("+", x));
}
function multiplier(s) {
return items_before_first("*", s);
}
function multiplicand(s) {
return items_after_first("*", s);
}
function deriv(exp, variable) {
display_list(exp);
return is_number(exp)
? 0
: is_variable(exp)
? (is_same_variable(exp, variable) ? 1 : 0)
: is_sum(exp)
? make_sum(deriv(addend(exp), variable),
deriv(augend(exp), variable))
: is_product(exp)
? make_sum(make_product(multiplier(exp),
deriv(multiplicand(exp),
variable)),
make_product(deriv(multiplier(exp),
variable),
multiplicand(exp)))
: error(exp, "unknown expression type -- deriv");
}
deriv(list("x", "*", 4), "x"); In the browser interpreter, this fails with Problem 2This took me forever to track down, but I figured out that the problem is in the builtin function It appears that the interpreter is locked based on the chapter. To get the desired functionality of checking for "+" in a list, we need a custom implementation of function contains_plus(s) {
return is_null(s)
? false
: is_string(head(s)) && head(s) === "+"
? true
: contains_plus(tail(s));
} and replace the calls function is_sum(x) {
return is_pair(x) && contains_plus(x);
} function is_product(x) {
return is_pair(x) && ! contains_plus(x);
} Running the code, we now get function items_before_first(op, s) {
return is_string(head(s)) && head(s) === op
? null
: pair(head(s),
items_before_first(op, tail(s)));
}
function items_after_first(op, s) {
return is_string(head(s)) && head(s) === op
? tail(s)
: items_after_first(op, tail(s));
} Problem 3:If we run what we've fixed so far in either a local JS environment or either Source §3 or Source §4 on sourceacademy, we get something like this: Running it locally with Node to get a proper stack trace: % node debug.js
list("x", "*", 4)
list(4)
.../node_modules/sicp/dist/stdlib/list.js:35
throw new Error('head(xs) expects a pair as argument xs, but encountered ' + (0, stringify_1.stringify)(xs));
^
Error: head(xs) expects a pair as argument xs, but encountered null
at head (.../node_modules/sicp/dist/stdlib/list.js:35:15)
at items_before_first (.../debug.js:18:12)
at items_before_first (.../debug.js:21:19)
at multiplier (.../debug.js:66:12)
at deriv (.../debug.js:81:39)
at deriv (.../debug.js:82:30)
at .../debug.js:90:1
at ModuleJob.run (node:internal/modules/esm/module_job:197:25)
at async Promise.all (index 0)
at async ESMLoader.import (node:internal/modules/esm/loader:337:24) We can see from the debug output that the last call to There are actually two ways of looking at the problem. One is that This could be done relatively simply by adding a check at the beginning: function deriv(exp, variable) {
return is_pair(exp) && length(exp) === 1 // check if the expression is a list of length 1
? deriv(head(exp), variable)
: is_number(exp)
... However, the problems in this chapter all give the constraint that We take the second approach to the problem: our predicates, selectors, and constructors should never return inputs to
Here is my proposed fix: add a new function function simplify_unary_list(s) {
return is_pair(s) && is_null(tail(s))
? head(s)
: s;
}
function addend(s) {
return simplify_unary_list(items_before_first("+", s));
}
function augend(s) {
return simplify_unary_list(items_after_first("+", s));
}
function multiplier(s) {
return simplify_unary_list(items_before_first("*", s));
}
function multiplicand(s) {
return simplify_unary_list(items_after_first("*", s));
} Finally, running this with Source §2, it works as expected. SummaryHere is the final version; it can be copy / pasted and executed in the Source Academy Source §2 interpreter. I've tested it with more complex inputs as well, and as far as I can tell it's a robust solution. // SICP JS 2.3.2
function is_variable(x) { return is_string(x); }
function is_same_variable(v1, v2) {
return is_variable(v1) && is_variable(v2) && v1 === v2;
}
function number_equal(exp, num) {
return is_number(exp) && exp === num;
}
function items_before_first(op, s) {
return is_string(head(s)) && head(s) === op
? null
: pair(head(s),
items_before_first(op, tail(s)));
}
function items_after_first(op, s) {
return is_string(head(s)) && head(s) === op
? tail(s)
: items_after_first(op, tail(s));
}
function simplify_unary_list(s) {
return is_pair(s) && is_null(tail(s))
? head(s)
: s;
}
function contains_plus(s) {
return is_null(s)
? false
: is_string(head(s)) && head(s) === "+"
? true
: contains_plus(tail(s));
}
function make_sum(a1, a2) {
return number_equal(a1, 0)
? a2
: number_equal(a2, 0)
? a1
: is_number(a1) && is_number(a2)
? a1 + a2
: list(a1, "+", a2);
}
// a sequence of terms and operators is a sum
// if and only if at least one + operator occurs
function is_sum(x) {
return is_pair(x) && contains_plus(x);
}
function addend(s) {
return simplify_unary_list(items_before_first("+", s));
}
function augend(s) {
return simplify_unary_list(items_after_first("+", s));
}
function make_product(m1, m2) {
return number_equal(m1, 0) || number_equal(m2, 0)
? 0
: number_equal(m1, 1)
? m2
: number_equal(m2, 1)
? m1
: is_number(m1) && is_number(m2)
? m1 * m2
: list(m1, "*", m2);
}
// a sequence of terms and operators is a product
// if and only if no + operator occurs
function is_product(x) {
return is_pair(x) && ! contains_plus(x);
}
function multiplier(s) {
return simplify_unary_list(items_before_first("*", s));
}
function multiplicand(s) {
return simplify_unary_list(items_after_first("*", s));
}
function deriv(exp, variable) {
return is_number(exp)
? 0
: is_variable(exp)
? (is_same_variable(exp, variable) ? 1 : 0)
: is_sum(exp)
? make_sum(deriv(addend(exp), variable),
deriv(augend(exp), variable))
: is_product(exp)
? make_sum(make_product(multiplier(exp),
deriv(multiplicand(exp),
variable)),
make_product(deriv(multiplier(exp),
variable),
multiplicand(exp)))
: error(exp, "unknown expression type -- deriv");
}
deriv(list("x", "*", 4), "x"); |
- Correct syntax errors - Fix usage of features not defined for the Source interpreter of Chapter 2 - Fix logic error handing single-item lists to deriv function
The solution to the second problem of 2.58 (Symbolic Differentiation) has several syntax errors that prevent it from executing in the browser:
And after fixing the actual program fails with an error that I haven't debugged yet:
The text was updated successfully, but these errors were encountered: