Форум программистов, компьютерный форум, киберфорум
Lisp
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.77/13: Рейтинг темы: голосов - 13, средняя оценка - 4.77
14 / 14 / 7
Регистрация: 11.05.2013
Сообщений: 225

SETQ не работает для безымянной функции

26.08.2013, 23:27. Показов 2692. Ответов 25
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
В самоучителе по Лиспу нашел, что можно лямбда-функцию присвоить переменной, и вызывать как обычную функцию:
Цитата из самоучителя
Если присвоить какому-либо атому в качестве значения корректное LAMBDA-выражение, то появляется возможность использовать это LAMBDA-выражение без повторного задания:
Lisp
1
2
3
4
5
6
(SETQ sq2 '(LAMBDA (x y) (+ (* x x) (* y y) )))
==> (LAMBDA (x y) (+ (* x x) (* y y)))
sq2
==> (LAMBDA (x y) (+ (* x x) (* y y)))
(sq2 6 7)
==> 85
Последний вызов (sq2 6 7) очень похож на вызов функции sq2. Сходство, однако, чисто внешнее. Атом sq2 не является именем функции (что будет разъяснено ниже, при рассмотрении списков свойств).


Задание: "Определите функцию add5(n), которая увеличивает числовой параметр n на 5, используя синтаксис λ-определения".
Мой код и реакция компилятора:
Lisp
1
2
3
4
5
6
(SETQ add5 '(LAMBDA (n) (SETQ n (+ n 5))))
==> (LAMBDA (n) (SETQ n (+ n 5)))
add5
==> (LAMBDA (n) (SETQ n (+ n 5)))
(add5 3)
==> EVAL: undefined function ADD5
Подскажите пожалуйста, что не так.
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
26.08.2013, 23:27
Ответы с готовыми решениями:

Избавляемся от безымянной функции
Здравствуйте! Есть такая функция: (defun f8 (mylist) (/ (apply #'+ mylist) (length mylist)) ) Она вычисляет среднее...

setf setq
Скажите, в чем разница между setf и setq?

Вычисление функции не работает для отрицательных чисел
double y, a; Console.WriteLine("ввод a"); a = Convert.ToDouble(Console.ReadLine()); if (a < 0) ...

25
Супер-модератор
Эксперт функциональных языков программированияЭксперт Python
 Аватар для Catstail
38161 / 21096 / 4306
Регистрация: 12.02.2012
Сообщений: 34,683
Записей в блоге: 14
26.08.2013, 23:42
Вот в чем дело. В Common Lisp (и в HomeLisp с ядром 13.x.x) так использовать setq-lambda не получится... Нужно так:

Lisp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
(SETQ add5 '(LAMBDA (n) (SETQ n (+ n 5))))
 
==> (LAMBDA (n) (SETQ n (+ n 5)))
Ñîçäàíà ãëîáàëüíàÿ ïåðåìåííàÿ add5
add5
 
==> (LAMBDA (n) (SETQ n (+ n 5)))
 
(add5 3)
 
EVFUN: Íå íàéäåíà ôóíêöèÿ ADD5
Ôóíêöèÿ: add5 Àðãóìåíòû: (3)
==> ERRSTATE
 
(funcall add5 3)
 
==> 8  ;; все верно!
А вот в HomeLisp с ядром 11.x.x (и, кажется, в Scheme) можно писать:

Lisp
1
2
3
4
5
6
7
(SETQ add5 '(LAMBDA (n) (SETQ n (+ n 5))))
 
==> (LAMBDA (n) (SETQ n (+ n 5)))
 
(add5 3)
 
==> 8
Приношу извинения...
0
4528 / 3522 / 358
Регистрация: 12.03.2013
Сообщений: 6,038
26.08.2013, 23:54
В Common Lisp два пространства имён: для переменных и для функций. В то же время функции - объекты первого класса, так что функция может быть значением переменной. Немного крышесносно.

Всякие "слова", которые вы пишете в программе (x, foo, let, setf и т. п.) - это символы, те самые, которые тип данных. С символом ассоциированы две "ячейки": для значения и для функции (value cell, function cell). Таким образом, символ может отдельно биндиться на значение и на некоторую функцию, которые никак не связаны друг с другом.

Принципиальная разница видна из основного правила вычисления списка: при вычислении списка (foo bar baz) для foo берётся значение из функциональной ячейки, для bar и baz - из ячейки-значения.

Когда вы используете setq, вы изменяете биндинг (я знаю, что там "ай", но на русский не ложится) ячейки-значения. Соответственно, когда вы пишете (add5 3), получается ошибка: ведь в функциональной ячейке add5 ничего нет! Если вы хотите сделать присваивание функциональной ячейке, можно сделать так:
Code
1
(setf (symbol-function 'add5) #'(lambda ...))
Хотя, конечно, обычно используется defun. А если функция является значением переменной, её обычно вызывают через funcall.

Два пространства имён - это одна из фич CL, которые делают его более громоздким и временами более корявым. Однако если приноровиться, очень удобно.
1
14 / 14 / 7
Регистрация: 11.05.2013
Сообщений: 225
26.08.2013, 23:56  [ТС]
К слову о Commo Lisp и HomeLisp. Я забыл сказать, что использую LispWorks. Тоже приношу извинения..
Цитата Сообщение от Catstail Посмотреть сообщение
Lisp
1
(funcall add5 3)
В LispWorks первый способ не работает.
Проверил еще в двух онлайн-компиляторах (первый, второй), там тоже не работает. Оба компилятора показывают одну ошибку:
FUNCALL: argument (LAMBDA (N) (SETQ N (+ N 5))) is not a function.
To get a function in the current environment, write (FUNCTION ...).
To get a function in the global environment, write (COERCE '... 'FUNCTION)
0
4528 / 3522 / 358
Регистрация: 12.03.2013
Сообщений: 6,038
27.08.2013, 00:06
Цитата Сообщение от Catstail Посмотреть сообщение
А вот в HomeLisp с ядром 11.x.x (и, кажется, в Scheme) можно писать:
В схеме, конечно, set! (или define, если на верхнем уровне), и не нужна кавычка перед lambda.

Добавлено через 9 минут
Цитата Сообщение от umc55555 Посмотреть сообщение
В LispWorks первый способ не работает.
Проверил еще в двух онлайн-компиляторах (первый, второй), там тоже не работает. Оба компилятора показывают одну ошибку:
FUNCALL: argument (LAMBDA (N) (SETQ N (+ N 5))) is not a function.
To get a function in the current environment, write (FUNCTION ...).
To get a function in the global environment, write (COERCE '... 'FUNCTION)
Когда setq-ите, пишите #'(lambda ... ). Шарп-кавычка обозначает взятие функционального содержимого. Впрочем, для лямбды можно и вовсе без кавычек. Кстати, setq морально устарел.

А вы задумались, как на самом деле работает ваша функция?
0
Супер-модератор
Эксперт функциональных языков программированияЭксперт Python
 Аватар для Catstail
38161 / 21096 / 4306
Регистрация: 12.02.2012
Сообщений: 34,683
Записей в блоге: 14
27.08.2013, 00:09
Цитата Сообщение от umc55555 Посмотреть сообщение
В LispWorks первый способ не работает.
- естественно, т.к. LW - это Common Lisp

Добавлено через 1 минуту
Цитата Сообщение от helter Посмотреть сообщение
Кстати, setq морально устарел.
- но работает...
Цитата Сообщение от helter Посмотреть сообщение
как на самом деле работает ваша функция?
- "... никакого самого дела нет" (В. Пелевин)
0
14 / 14 / 7
Регистрация: 11.05.2013
Сообщений: 225
27.08.2013, 00:17  [ТС]
Цитата Сообщение от helter Посмотреть сообщение
Всякие "слова", которые вы пишете в программе (x, foo, let, setf и т. п.) - это символы, те самые, которые тип данных. С символом ассоциированы две "ячейки": для значения и для функции (value cell, function cell). Таким образом, символ может отдельно биндиться на значение и на некоторую функцию, которые никак не связаны друг с другом.
Если я правильно понял, в одной переменной/символе могут лежать и значение переменной, и функция?

Цитата Сообщение от helter Посмотреть сообщение
А вы задумались, как на самом деле работает ваша функция?
Не очень понимаю что вы имеете в виду, но скорее всего ответ "нет".

Цитата Сообщение от helter Посмотреть сообщение
Lisp
1
(setf (symbol-function 'add5) #'(lambda ...))
Чуть изменил ваш вариант. Такой код
Lisp
1
(setf add5 '(LAMBDA (n) (SETQ n (+ n 5))))
сработал в LispWorks почему-то только один раз (при вызове функции вывелся правильный ответ), а в онлайн-компиляторах ошибка: "EVAL: undefined function ADD5".
0
4528 / 3522 / 358
Регистрация: 12.03.2013
Сообщений: 6,038
27.08.2013, 00:42
Цитата Сообщение от umc55555 Посмотреть сообщение
Если я правильно понял, в одной переменной/символе могут лежать и значение переменной, и функция?
Точно. Например, вы определяете функцию
Code
1
(defun node ...)
а потом всегда можете смело использовать node как переменную, не боясь, что она затенит функцию. Думается, так правильно мыслить: функциональная ячейка - для "нетленки", определений верхнего уровня, которые фактически расширяют язык; то есть функциональная ячейка для расширения языка. А ячейка значения - временно взял символ попользоваться. (Кстати, когда значение имеет постоянный характер - в случае глобальных переменных и констант - вступают в силу конвенции именования: ушки, крестики. Видимо, неслучайно.)

Цитата Сообщение от umc55555 Посмотреть сообщение
Не очень понимаю что вы имеете в виду, но скорее всего ответ "нет".
Когда вы вызываете функцию, внутри неё n биндится на аргумент: например, на 3. А присваиванием вы перебинживаете его на 8. Зачем??? К счастью, оператор присваивания в лиспе возвращает значение, которое и получается значением функции. То есть вы пишете присваивание, которое совсем не нужно и не используется, а пользуетесь только тем, что при присваивании возвращается "правая часть". Гораздо естественнее ту же функцию записать в виде
Code
1
(lambda (n) (+ n 5))
Вообще, преобладающей парадигмой в лиспе является функциональная, и к присваиваниям следует относиться настороженно. Как пишет Грэм, представьте, что присваивание облагается небольшим налогом.

Цитата Сообщение от umc55555 Посмотреть сообщение
сработал в LispWorks
Непонятно, почему. Кавычкой вы превратили список из лямбда-выражения в обычный список с символами и пр. - в данные.
1
Заблокирован
27.08.2013, 00:44
я setq только с рекурсивными лямбдами применяю, когда лень функции писать
Lisp
1
2
3
4
5
6
7
8
9
10
11
12
13
(defun incdec-uninstall( / str f)
    (setenv "ACAD"(substr(setq str(apply 'strcat(mapcar '(lambda(x)
        (if(wcmatch x "*INCDEC*")""(strcat x ";")))
            ((setq f(lambda(s2 p2 / i)(cond
                ((= s2 "")nil)
                ((setq i((lambda(s1 p1 / i r)
                (setq i 1)(repeat(-(strlen s1)(strlen p1))
                (if(= p1(substr s1 1(strlen p1)))
                    (if(not r)(setq r(1- i))))
                    (setq s1(substr s1 2(1-(strlen s1)))i(1+ i)))r)s2 p2))
                    (cons(substr s2 1 i)(f(substr s2(+ 2 i))p2)))
                        (T(list s2)))))(getenv "ACAD")";"))))1(1-(strlen str))))
                                (command "_.menuunload" "INCDEC")(princ))
Если честно навскидку сам не скажу что тут и куда
0
Эксперт функциональных языков программированияЭксперт Java
 Аватар для korvin_
4575 / 2773 / 491
Регистрация: 28.04.2012
Сообщений: 8,760
27.08.2013, 01:21
Цитата Сообщение от helter Посмотреть сообщение
Два пространства имён - это одна из фич CL
На самом деле больше. То ли у Грэма, то ли в PCL был список, в общей сложности около семи.

Цитата Сообщение от ur_naz Посмотреть сообщение
я setq только с рекурсивными лямбдами применяю, когда лень функции писать
В CL есть label для этого.
1
Супер-модератор
Эксперт функциональных языков программированияЭксперт Python
 Аватар для Catstail
38161 / 21096 / 4306
Регистрация: 12.02.2012
Сообщений: 34,683
Записей в блоге: 14
27.08.2013, 07:56
Цитата Сообщение от umc55555 Посмотреть сообщение
В LispWorks первый способ не работает.
- это который?

Добавлено через 4 минуты
Цитата Сообщение от helter Посмотреть сообщение
Непонятно, почему
- проверил. С квотирование лямбда-выражение не работает
1
1075 / 968 / 113
Регистрация: 04.11.2012
Сообщений: 1,013
27.08.2013, 10:54
Lisp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
;Вариант HomeLisp без #. Версия 1.13.17 
(setq add5 '(lambda (n) (setq n (+ n 5))))
 
==> (LAMBDA (n) (SETQ n (+ n 5)))
 
(funcall add5 3)
 
==> 8
 
(apply add5 (list 3))
 
==> 8
 
Никаких проблем.
 
;Вариант LispWorks с #
> (setq add5 #'(lambda (n) (setq n (+ n 5))))
#<anonymous interpreted function 200A756A>
 
> (funcall add5 3)
8
 
;Вариант LispWorks без #
> (setq add5 '(lambda (n) (setq n (+ n 5))))
(LAMBDA (N) (SETQ N (+ N 5)))
 
> (eval (cons add5 (list 3)))
8
 
> (apply add5 (list 3))
 
Error: Argument to apply/funcall is not a function: (LAMBDA (N) (SETQ N (+ N 5))
Не понятен результат последнего вызова. Раньше уже натыкался, и просто исправлял на (eval (cons ...
Но почему, интересно же?! Ответ, что это не функция, меня не полностью устраивает.

Добавлено через 19 минут
Пока что остается успокоиться на том, что apply можно применять только к символу, который ранее определен как имя функции...
1
Заблокирован
27.08.2013, 11:34
Цитата Сообщение от Lambdik Посмотреть сообщение
Не понятен результат последнего вызова.
как я понимаю это примерно то же что ((quote add5) 3)
1
4528 / 3522 / 358
Регистрация: 12.03.2013
Сообщений: 6,038
27.08.2013, 12:19
Цитата Сообщение от Lambdik Посмотреть сообщение
Не понятен результат последнего вызова. Раньше уже натыкался, и просто исправлял на (eval (cons ...
Но почему, интересно же?! Ответ, что это не функция, меня не полностью устраивает.
Ну так это и не функция. А список. С помощью большего числа кавычек, ваше значение add5 можно записать ('lambda ('n) ('setq 'n ('+ 'n 5))). То есть при выполнении присваивания ни lambda, ни + не имеют специального значения и выступают просто как символы.

Добавлено через 55 секунд
И да, если вы вынуждены использовать eval, вероятно, вы что-то делаете не так.
2
Супер-модератор
Эксперт функциональных языков программированияЭксперт Python
 Аватар для Catstail
38161 / 21096 / 4306
Регистрация: 12.02.2012
Сообщений: 34,683
Записей в блоге: 14
27.08.2013, 12:35
Еще пару слов (HomeLisp-13)

Lisp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
(let ((a 5)) (setq adda '(lambda (x) (+ x a))))
 
==> (LAMBDA (x) (+ x a)) ;; Просто список, но funcall HomeLisp поймет его правильно
 
(funcall adda 6)
 
Assoc: Символ a не имеет значения (не связан). ;; свободная переменная a не имеет значения
==> ERRSTATE
 
(let ((a 5)) (setq adda (lambda (x) (+ x a))))
 
==> (CLOSURE (x) ((+ x a)) ((a 5)))  ;; здесь создается замыкание !!!
 
(funcall adda 6)
 
==> 11
1
1075 / 968 / 113
Регистрация: 04.11.2012
Сообщений: 1,013
27.08.2013, 13:40
Цитата Сообщение от helter Посмотреть сообщение
Ну так это и не функция. А список.
Да, но почему тогда в HomeLisp прокатило?
Цитата Сообщение от Catstail Посмотреть сообщение
(CLOSURE (x) ((+ x a)) ((a 5))) ;; здесь создается замыкание
Хорошо что выводится такое сообщение, сразу видно какое значение у переменных внутри.
1
Супер-модератор
Эксперт функциональных языков программированияЭксперт Python
 Аватар для Catstail
38161 / 21096 / 4306
Регистрация: 12.02.2012
Сообщений: 34,683
Записей в блоге: 14
27.08.2013, 14:28
Цитата Сообщение от Lambdik Посмотреть сообщение
Хорошо что выводится такое сообщение, сразу видно какое значение у переменных внутри.
- я старался ...
1
14 / 14 / 7
Регистрация: 11.05.2013
Сообщений: 225
27.08.2013, 22:26  [ТС]
1.
Цитата Сообщение от helter Посмотреть сообщение
А присваиванием вы перебинживаете его на 8. Зачем???
В задании написано "увеличивает параметр на 5", вот я и сделал точно то, что написано в задании. Хотя я мог неправильно понять формулировку. И согласен, что так буквально не стоило воспринимать, тоже не вижу смысла в таком присваивании.

2. Что значит этот ответ компилятора? Возвращает адрес функции в памяти?
"#<anonymous interpreted function 21BD975A>"
Он отвечает так на вариант helter'а:
Lisp
1
(setf (symbol-function 'add5) #'(LAMBDA (n) (+ n 5)))
По незнанию мне казалось, что такой ответ означает ошибку (забыл об этом написать в прошлом посте), и только сейчас вызвал функцию - все работает. В принципе вопрос решен, только непонятно почему онлайн-компиляторы не выводят ничего (компилируется успешно, но ничего не выводят).


3.
Цитата Сообщение от Lambdik Посмотреть сообщение
Lisp
1
2
3
4
5
;Вариант LispWorks с #
> (setq add5 #'(lambda (n) (setq n (+ n 5))))
#<anonymous interpreted function 200A756A>
> (funcall add5 3)
8
Всегда возвращает T. Возможно, разница в версиях? У меня 6.1.1

4. В "варианте LispWorks без #" мне тоже не нравится eval.

Всем спасибо.
0
27.08.2013, 22:31

Не по теме:

Цитата Сообщение от umc55555 Посмотреть сообщение
В принципе вопрос решен, только непонятно почему онлайн-компиляторы не выводят ничего (компилируется успешно, но ничего не выводят).
Зачем вам онлайн-компиляторы и проприетарщина? Поставили бы CLISP себе или вообще LispBox.

0
14 / 14 / 7
Регистрация: 11.05.2013
Сообщений: 225
27.08.2013, 22:37  [ТС]
Цитата Сообщение от Catstail Посмотреть сообщение
Цитата Сообщение от umc55555 Посмотреть сообщение
В LispWorks первый способ не работает.
- это который?
Вы ведь сами уже ответили:
Цитата Сообщение от Catstail Посмотреть сообщение
Цитата Сообщение от umc55555 Посмотреть сообщение
В LispWorks первый способ не работает.
- естественно, т.к. LW - это Common Lisp
"первый способ" - это я писал про ваш способ в самом первом сообщении:
Lisp
1
(SETQ add5 '(LAMBDA (n) (SETQ n (+ n 5))))
С решеткой перед кавычкой он заработал. К моему удивлению .

Цитата Сообщение от helter Посмотреть сообщение
Зачем вам онлайн-компиляторы и проприетарщина? Поставили бы CLISP себе или вообще LispBox.
CLisp пробовал, не понравилась стилизация под командную строку)).
LispBox не знаю что такое, но LispWorks меня пока вполне устраивает. Может как-нибудь посмотрю LispBox.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
27.08.2013, 22:37
Помогаю со студенческими работами здесь

Не работает шаблон функции для типа float
Доброго времени суток! Написал простой код с шаблоном функции, находит индекс элемента в массивах разных типов. Но в массиве float выдаёт...

Работает ли onClick Input'a для вызова функции в коде бехайнд?
Привет всем! Вот решил опробовать новый форум, чтобы получить совет. Пишу небольшой search, И мои 2 вопроса такие: 1. на странице...

Не работает нахождение СПМ для разной длинны окна (выделяющей функции)
Прошу помочь устранить ошибку в программе. %ФУНКЦИЯ РАСЧЕТА СПМ МЕТОДОМ УЭЛЧА function zadanie4(x) dlit=input('ВВЕДИТЕ...

Составить программу для вычисления значения следующей функции, код работает некорректно
Примерчик: Как сделал я: CLS FOR x = -(.5) TO .5 STEP .025 y = ((1 - EXP(2 * x)) / (1 + EXP(2 * x))) * ((SIN(2 * x)) ^ 2) ...

Почему не работает программа-пример для демонстрации работы функции strcmp (из книги Шилдта)?
Здравствуйте, помогите пожалуйста разобраться, почему программа не выполняется как надо. Программа-пример, для демонстрации работы функции...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Access
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут. В век Веб все очень привыкли к дизайну Single-Page-Application . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru