возвращает функцию, добавляющую её аргумент к аргументу
>f
, то есть, ей нужен доступ к локальной области видимости внутри
>f
для использования переменной
>a
.
>run("do(define(f, fun(a, fun(b, +(a, b)))),",
> " print(f(4)(5)))");
>// → 9
Объясните, используя определение формы >fun
, какой механизм позволяет этой конструкции работать.
Хорошо было бы иметь комментарии в Egg. К примеру, мы могли бы игнорировать оставшуюся часть строки, встречая символ >\#
– так, как это происходит с >//
в JavaScript.
Большие изменения в парсере делать не придётся. Мы просто поменяем >skipSpace
, чтобы она пропускала комментарии, будто они являются пробелами – и во всех местах, где вызывается >skipSpace
, комментарии тоже будут пропущены. Внесите это изменение.
>// Поменяйте старую функцию
>function skipSpace(string) {
> var first = string.search(/\S/);
> if (first == -1) return "";
> return string.slice(first);
>}
>console.log(parse("# hello\nx"));
>// → {type: "word", name: "x"}
>console.log(parse("a # one\n # two\n()"));
>// → {type: "apply",
>// operator: {type: "word", name: "a"},
>// args: []}
Сейчас мы можем присвоить переменной значение только через >define
. Эта конструкция работает как при присвоении старым переменным, так и при создании новых.
Эта неоднозначность приводит к проблемам. Если вы пытаетесь присвоить новое значение нелокальной переменной, вместо этого вы определяете локальную с таким же именем. (Некоторые языки так и делают, но мне это всегда казалось дурацким способом работы с областью видимости).
Добавьте форму >set
, схожую с >define
, которая присваивает переменной новое значение, обновляя переменную во внешней области видимости, если она не задана в локальной. Если переменная вообще не задана, швыряйте >ReferenceError
(ещё один стандартный тип ошибки).
Техника представления областей видимости в виде простых объектов, до сего момента бывшая удобной, теперь будет вам мешать. Вам может понадобиться функция >Object.getPrototypeOf
, возвращающая прототип объекта. Также помните, что область видимости не наследуется от >Object.prototype
, поэтому если вам надо вызвать на них >hasOwnProperty
, придётся использовать такую неуклюжую конструкцию:
>Object.prototype.hasOwnProperty.call(scope, name);
Это вызывает метод >hasOwnProperty
прототипа >Object
и затем вызывает его на объекте >scope
.
>specialForms["set"] = function(args, env) {
> // Ваш код
>};
>run("do(define(x, 4),",
> " define(setx, fun(val, set(x, val))),",
> " setx(50),",
> " print(x))");
>// → 50
>run("set(quux, true)");