EVAL: ((USER "Worminator") 'FORMAT) is not a function name; try using a symbol instead
Почему? Можно ли как-то использовать второй вариант? Что означает not a function name — вообще не понял. И что делает funcall? Зачем нужна apply — ясно, она берет аргументы для вызова из списка, а вот с этой функцией непонятно. В другом диалекте Лиспа, Scheme, кстати, не нашел funcall (или там другое имя для нее).
Как-то запутанно все... В учебнике Святослава Лаврова, по которому когда-то учил Лисп, funcall совершенно не упоминалась, там говорилось, что выражение (f a1 ... aN) просто применяет значение f (которое должно быть лямбдой) к аругментам a1-aN и выдает результат. И вообще весь Лисп описывался 10 базовыми функциями: car, cdr, cons, atom, eq, cond, lambda, defun, setq и quote.
Как запру я тебя за железный замок, за дубовую дверь окованную,
Чтоб свету божьего ты не видела, мое имя честное не порочила…
М. Лермонтов. Песня про царя Ивана Васильевича, молодого опричника и удалого купца Калашникова
Схема — это Lisp-1. Common Lisp — это Lisp-N, т.е. буквально много пространств имен. Функции и переменные в разных пространствах имен.
В начале формы ищет название функции из пространства имен функций, а у вас, вообще, ячейка сons! Отсюда у вас недопонимание с компилятором.
Зачем это нужно? Сильно упрощает проверку кода при компиляции для динамического языка. Язык не статический, а именно динамический. Такая штука в итоге помогает создавать приложения с большим объемом кода, т.е. позволяет снизить сложность программирования.
А что касается укороченной формы "((lambda ...) arg)", то это небольшое отступление от общих правил, упрощение, да и просто архаизм, хотя лично мне нравится.
Здравствуйте, dsorokin, Вы писали:
D>В начале формы ищет название функции из пространства имен функций, а у вас, вообще, ячейка сons! Отсюда у вас недопонимание с компилятором.
Если несложно, то можно объяснить, почему в этом случае funcall для вызова не требуется, а в примере с ООП обязателен?
(print (
(lambda (x y)
(format NIL "~d + ~d = ~d" x y (+ x y))
)
2
3
)
)
У меня из функции-конструктора User возвращается та же самая lambda вроде? В чем разница между этими примерами?
Сначала думал, из-за замыканий (поля id и name), но нет, вроде без них то же самое.
То есть в 1-м случае можно использовать анонимную функцию, а во 2-м обязательно указывать имя.
В JavaScript никакой разницы, передавать имя функции или анонимную функцию, значение типа function:
function User(name) {
var id;
if (!('counter' in User)) {
User.counter = 0;
}
User.counter++;
id = User.counter;
return {
'getId': function() { return id; },
'getName': function() { return name; },
'data': function() { return [id, name]; },
'format': function(f) { return f.replace('%d', id).replace('%s', name); }
};
}
Обязательное создание имен в глобальном namespace — это, скорее, больше походит на статические языки, в частности отсутствие анонимных функций (хотя бы без замыканий) это огромный, жирный минус Си. Частично исправленный в GCC (но это нестандартное расширение). На каждый вызов qsort, таймера и т.д. создавать отдельную функцию и придумывать ей имя, всегда это приводило в бешенство. Разумеется, в динамическом языке такой мусор недопустим, не нужно превращать код в помойку. Даже в Java, еще до появления лямбд, пытались что-то с этим сделать, ввели анонимные классы. А в C# изначально сдеалали делегаты.
D>По Common Lisp есть хороший учебник: Практическое использование Common Lisp
Спасибо, буду изучать. Похоже, там со времен Джона Маккарти в 1958 напридумывали всего... По статьям из интернета теперь не разберешься, а ведь изначально это был один из самых простых языков. Столяров, пожалуй, прав, когда призывает расстреливать любых стандартизаторов из комитетов.
Как запру я тебя за железный замок, за дубовую дверь окованную,
Чтоб свету божьего ты не видела, мое имя честное не порочила…
М. Лермонтов. Песня про царя Ивана Васильевича, молодого опричника и удалого купца Калашникова
В последнем случае вообще нет имен, для исключения проблем с namespace'ами.
Как запру я тебя за железный замок, за дубовую дверь окованную,
Чтоб свету божьего ты не видела, мое имя честное не порочила…
М. Лермонтов. Песня про царя Ивана Васильевича, молодого опричника и удалого купца Калашникова
У вас функция "User" создает лямбда-выражение. Чтобы его вызвать опосредованно, необходимо применить функцию funcall, передав аргументом соответствующее лямбда-выражение:
(funcall (User name))
Как я написал выше, первым элементом формы ожидается имя функции (которое ищется в пространстве имен функций). Сам "funcall" — это функция, такая же как и ваш "User". Поэтому все правильно.
Здесь мы для простоты опустим макросы и специальные формы, о которых читайте уже в книге, которую я посоветовал (кстати, в интернете должна быть легальная версия PDF на английском для всех желающих).
У вас там цепочка лямбда-выражений. Поэтому "funcall" — это именно то, что нужно.
Теперь если вы по ошибке первым поставили выражение, возвращаемое из User:
((User name) 'format)
То это так не работает в Common Lisp, потому что первым элементом формы опять-таки ожидается именно название функции. А где у вас здесь название функции? У вас там ячейка cons с содержимым "(User name)", и компилятору лиспа это не нравится. Все ожидаемо.
Теперь по поводу выражения типа:
((lambda (x y)
(format NIL "~d + ~d = ~d" x y (+ x y)))
2 3)
Это допустимая сокращенная запись для более полной формы:
(funcall
(lambda (x y)
(format NIL "~d + ~d = ~d" x y (+ x y)))
2 3)
То сокращение возникло давно в языке. Оно роднит Common Lisp с той же Схемой. Однако, это просто тот случай, который распознают компиляторы. В остальных случаях нужно использовать "funcall" или "apply", поскольку Lisp-N. За деталями прошу обратиться все-таки к посоветованной мною книге, а не к форуму.
Что касается Столярова. Не надо лисп изучать по его книгам! Я глубоко убежден, что автор должен учить тем языкам, которые ему нравятся, которые вызывают у него приятные чувства. Если языки автору противны, вызывают отторжение, то и писать о них ничего не надо — выглядит со стороны смешно и глупо, да и молодых людей может травмировать такая книга, повести по ложному пути. Пожалуй, на этом обсуждение талмуда Столярова закончу.
Здравствуйте, Worminator X, Вы писали:
WX>Как-то запутанно все... В учебнике Святослава Лаврова, по которому когда-то учил Лисп, funcall совершенно не упоминалась, там говорилось, что выражение (f a1 ... aN) просто применяет значение f (которое должно быть лямбдой) к аругментам a1-aN и выдает результат. И вообще весь Лисп описывался 10 базовыми функциями: car, cdr, cons, atom, eq, cond, lambda, defun, setq и quote.
"вообще весь Лисп описывался 10 базовыми функциями" -- это Lisp 1.5, или типа того, конца 50-х — начала 60-х.
Стандарт Common Lisp вышел в 1994-м году и описывает гораздо более поздний Лисп, который описывается куда большим количеством функций, типов, особых форм и прочего.
WX>простой пример с ООП