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

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

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

Author24 — интернет-сервис помощи студентам
В самоучителе по Лиспу нашел, что можно лямбда-функцию присвоить переменной, и вызывать как обычную функцию:
Цитата из самоучителя
Если присвоить какому-либо атому в качестве значения корректное 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
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
26.08.2013, 23:27
Ответы с готовыми решениями:

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

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

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

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

25
Модератор
Эксперт функциональных языков программированияЭксперт Python
36609 / 20336 / 4222
Регистрация: 12.02.2012
Сообщений: 33,660
Записей в блоге: 13
26.08.2013, 23:42 2
Вот в чем дело. В 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
4527 / 3521 / 358
Регистрация: 12.03.2013
Сообщений: 6,038
26.08.2013, 23:54 3
В Common Lisp два пространства имён: для переменных и для функций. В то же время функции - объекты первого класса, так что функция может быть значением переменной. Немного крышесносно.

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

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

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

Два пространства имён - это одна из фич CL, которые делают его более громоздким и временами более корявым. Однако если приноровиться, очень удобно.
1
14 / 14 / 7
Регистрация: 11.05.2013
Сообщений: 225
26.08.2013, 23:56  [ТС] 4
К слову о 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
4527 / 3521 / 358
Регистрация: 12.03.2013
Сообщений: 6,038
27.08.2013, 00:06 5
Цитата Сообщение от 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
36609 / 20336 / 4222
Регистрация: 12.02.2012
Сообщений: 33,660
Записей в блоге: 13
27.08.2013, 00:09 6
Цитата Сообщение от umc55555 Посмотреть сообщение
В LispWorks первый способ не работает.
- естественно, т.к. LW - это Common Lisp

Добавлено через 1 минуту
Цитата Сообщение от helter Посмотреть сообщение
Кстати, setq морально устарел.
- но работает...
Цитата Сообщение от helter Посмотреть сообщение
как на самом деле работает ваша функция?
- "... никакого самого дела нет" (В. Пелевин)
0
14 / 14 / 7
Регистрация: 11.05.2013
Сообщений: 225
27.08.2013, 00:17  [ТС] 7
Цитата Сообщение от 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
4527 / 3521 / 358
Регистрация: 12.03.2013
Сообщений: 6,038
27.08.2013, 00:42 8
Цитата Сообщение от umc55555 Посмотреть сообщение
Если я правильно понял, в одной переменной/символе могут лежать и значение переменной, и функция?
Точно. Например, вы определяете функцию
Код
(defun node ...)
а потом всегда можете смело использовать node как переменную, не боясь, что она затенит функцию. Думается, так правильно мыслить: функциональная ячейка - для "нетленки", определений верхнего уровня, которые фактически расширяют язык; то есть функциональная ячейка для расширения языка. А ячейка значения - временно взял символ попользоваться. (Кстати, когда значение имеет постоянный характер - в случае глобальных переменных и констант - вступают в силу конвенции именования: ушки, крестики. Видимо, неслучайно.)

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

Цитата Сообщение от umc55555 Посмотреть сообщение
сработал в LispWorks
Непонятно, почему. Кавычкой вы превратили список из лямбда-выражения в обычный список с символами и пр. - в данные.
1
Заблокирован
27.08.2013, 00:44 9
я 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
4486 / 2721 / 485
Регистрация: 28.04.2012
Сообщений: 8,590
27.08.2013, 01:21 10
Цитата Сообщение от helter Посмотреть сообщение
Два пространства имён - это одна из фич CL
На самом деле больше. То ли у Грэма, то ли в PCL был список, в общей сложности около семи.

Цитата Сообщение от ur_naz Посмотреть сообщение
я setq только с рекурсивными лямбдами применяю, когда лень функции писать
В CL есть label для этого.
1
Модератор
Эксперт функциональных языков программированияЭксперт Python
36609 / 20336 / 4222
Регистрация: 12.02.2012
Сообщений: 33,660
Записей в блоге: 13
27.08.2013, 07:56 11
Цитата Сообщение от umc55555 Посмотреть сообщение
В LispWorks первый способ не работает.
- это который?

Добавлено через 4 минуты
Цитата Сообщение от helter Посмотреть сообщение
Непонятно, почему
- проверил. С квотирование лямбда-выражение не работает
1
1050 / 944 / 107
Регистрация: 04.11.2012
Сообщений: 974
Записей в блоге: 3
27.08.2013, 10:54 12
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 13
Цитата Сообщение от Lambdik Посмотреть сообщение
Не понятен результат последнего вызова.
как я понимаю это примерно то же что ((quote add5) 3)
1
4527 / 3521 / 358
Регистрация: 12.03.2013
Сообщений: 6,038
27.08.2013, 12:19 14
Цитата Сообщение от Lambdik Посмотреть сообщение
Не понятен результат последнего вызова. Раньше уже натыкался, и просто исправлял на (eval (cons ...
Но почему, интересно же?! Ответ, что это не функция, меня не полностью устраивает.
Ну так это и не функция. А список. С помощью большего числа кавычек, ваше значение add5 можно записать ('lambda ('n) ('setq 'n ('+ 'n 5))). То есть при выполнении присваивания ни lambda, ни + не имеют специального значения и выступают просто как символы.

Добавлено через 55 секунд
И да, если вы вынуждены использовать eval, вероятно, вы что-то делаете не так.
2
Модератор
Эксперт функциональных языков программированияЭксперт Python
36609 / 20336 / 4222
Регистрация: 12.02.2012
Сообщений: 33,660
Записей в блоге: 13
27.08.2013, 12:35 15
Еще пару слов (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
1050 / 944 / 107
Регистрация: 04.11.2012
Сообщений: 974
Записей в блоге: 3
27.08.2013, 13:40 16
Цитата Сообщение от helter Посмотреть сообщение
Ну так это и не функция. А список.
Да, но почему тогда в HomeLisp прокатило?
Цитата Сообщение от Catstail Посмотреть сообщение
(CLOSURE (x) ((+ x a)) ((a 5))) ;; здесь создается замыкание
Хорошо что выводится такое сообщение, сразу видно какое значение у переменных внутри.
1
Модератор
Эксперт функциональных языков программированияЭксперт Python
36609 / 20336 / 4222
Регистрация: 12.02.2012
Сообщений: 33,660
Записей в блоге: 13
27.08.2013, 14:28 17
Цитата Сообщение от Lambdik Посмотреть сообщение
Хорошо что выводится такое сообщение, сразу видно какое значение у переменных внутри.
- я старался ...
1
14 / 14 / 7
Регистрация: 11.05.2013
Сообщений: 225
27.08.2013, 22:26  [ТС] 18
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
helter
27.08.2013, 22:31
  #19

Не по теме:

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

0
14 / 14 / 7
Регистрация: 11.05.2013
Сообщений: 225
27.08.2013, 22:37  [ТС] 20
Цитата Сообщение от 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
27.08.2013, 22:37
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
27.08.2013, 22:37
Помогаю со студенческими работами здесь

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

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

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

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


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

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru