lambda функция объясните понятно.
| Правила | Регистрация | Пользователи | Сообщения за день |  Справка по форуму | Файлообменник |

Вернуться   Форум DWG.RU > Программное обеспечение > Программирование > lambda функция объясните понятно.

lambda функция объясните понятно.

Ответ
Поиск в этой теме
Непрочитано 21.11.2012, 16:31 #1
lambda функция объясните понятно.
Kirill_Ja
 
Мурманск
Регистрация: 28.07.2008
Сообщений: 208

Функция Lambda очень часто встречается в текстах кодов на форуме. У Николая Полещука в книге описана как функция для того, чтобы прямо в тексте программы определить и тут же выполнить пользовательскую функцию. В документации для разработчиков AutoCad тоже какой-то неочевидный и не очень понятный пример.

В общем как-то так.

Объясните понятно на примере как это и зачем именно определять функцию одноразового применения.
Просмотров: 15734
 
Непрочитано 21.11.2012, 17:03
#2
gomer

строю, ломаю
 
Регистрация: 03.04.2008
Украина
Сообщений: 5,515


Код:
[Выделить все]
 (type (lambda (x) (/ 1. (* x x)))) 
(apply '+ (mapcar '(lambda (x) (/ 1. (* x x))) '(1 2 3)))
;; (1/1^2) + (1/2^2) + (1/3^2) сумма обратных квадратов
или так
Код:
[Выделить все]
 ((lambda (f lst)
   (apply (function +) (mapcar (function f) lst))
 )
  (lambda (x) (/ 1. (* x x)))
  '(1 2 3)
)

Последний раз редактировалось gomer, 21.11.2012 в 17:19. Причина: коряво получилось
gomer вне форума  
 
Непрочитано 21.11.2012, 17:13
#3
Дима_

Продуман
 
Регистрация: 22.02.2007
Питер
Сообщений: 2,839


Цитата:
Сообщение от Kirill_Ja Посмотреть сообщение
У Николая Полещука в книге описана как функция для того, чтобы прямо в тексте программы определить и тут же выполнить пользовательскую функцию.
Не знаю не читал, но насчет "тут же выполнить" кто-то из Вас или ошибся, или не так понял.
Lambda это функция возращающая функцию созданную на основе ее тела. В "классическом" программировании функции (или операторы - в зависимости от семантики языка) обязательно должны иметь какое-то имя, в лиспе оно зачастую не нужно и функцию можно напрямую передавать другой функции (и внутри последней она будет носить имя аргумента), или применить к ней аргументы (то есть выполнить).
__________________
Когда в руках молоток все вокруг кажется гвоздями.
Дима_ вне форума  
 
Непрочитано 21.11.2012, 17:28
#4
Do$

AutoCAD/Civil3D LISP/C#
 
Регистрация: 15.08.2008
Санкт-Петербург
Сообщений: 1,701
Отправить сообщение для Do$ с помощью Skype™


1. Для использования в функциях, принимающих в качестве аргумента какую-либо функцию. Пример такой функции - vl-remove-if-not. Мне нужно, например, пройтись по списку из ename блоков и найти в нем блоки с именем "Имя". Стандартной функции, которая одновременно извлекает из ename имя и сверяет с заданной строкой, не существует. Поэтому, я мог бы написать так:
Код:
[Выделить все]
(defun get-name-and-wcmatch (ent / name) (and (setq name (cdr (assoc 2 (entget ent)))) (= name "Имя")))
(vl-remove-if-not (function get-name-and-wcmatch) <тут ename-список>)
Но мне в дальнейшем моя функция get-name-and-wcmatch нигде не понадобится, поэтому мне бессмысленно ее запоминать. Проще "впихнуть" все в одно выражение, тут уже не обойтись без лямбды:
Код:
[Выделить все]
(vl-remove-if-not (function (lambda (ent / name) (and (setq name (cdr (assoc 2 (entget ent)))) (= name "Имя")))) <тут ename-список>)
2. Я частенько лямбду использую для отделения функциональных кусков кода, чтобы можно было "на месте" задать локальные переменные, а не тащить их к самому верхнему списку переменных:
Код:
[Выделить все]
(defun <программа> (<тут могут быть агрументы> / <основной список локальных переменных>)
<тут какой-то код>
((lambda (<тут могут быть аргументы> / <локальные переменные участка кода>) <участок кода>) <тут могут вычисляться/задаваться аргументы>)
<и тут какой-то код>
)
Надеюсь, что можно понять начинающему то, о чем я тут написал
Do$ вне форума  
 
Автор темы   Непрочитано 21.11.2012, 17:29
#5
Kirill_Ja


 
Регистрация: 28.07.2008
Мурманск
Сообщений: 208
<phrase 1=


Первый код я понял. Если по порядку мы задаем Lambda(x) и применяем ее ко всем элементам списка '(1 2 3) При этом Lambda не компилируется.
Потом применяем '+ к списку который получился после применения L к списку исх данных '(1 2 3)


Чего-то я второй пример не очень понял

Ладно. Книга мне в помощь. Ушел читать. Если есть еще примеры или можете разобрать второй -> буду благодарен.
Kirill_Ja вне форума  
 
Непрочитано 21.11.2012, 17:43
#6
Кулик Алексей aka kpblc
Moderator

LISP, C# (ACAD 200[9,12,13,14])
 
Регистрация: 25.08.2003
С.-Петербург
Сообщений: 40,450


Еще кусок - http://autolisp.ru/2009/09/16/lambda-functions/
Хотя наверняка меня сейчас закидают гнилыми помидорами...
__________________
Моя библиотека lisp-функций
---
Обращение ко мне - на "ты".
Все, что сказано - личное мнение.
Кулик Алексей aka kpblc вне форума  
 
Непрочитано 21.11.2012, 17:55
#7
gomer

строю, ломаю
 
Регистрация: 03.04.2008
Украина
Сообщений: 5,515


Цитата:
Сообщение от Дима_ Посмотреть сообщение
Lambda это функция возращающая функцию
Код:
[Выделить все]
 (eq (type <=) (type (lambda (*) (*))))
добавим немного эротики... то, что возвращает лямбда больше похоже на указатель на пользовательскую функцию
>Кулик Алексей aka kpblc, не SUBR, а USUBR
gomer вне форума  
 
Непрочитано 21.11.2012, 18:02
#8
Дима_

Продуман
 
Регистрация: 22.02.2007
Питер
Сообщений: 2,839


А строка возращает указатель на строку - нет такого понятия в лиспе - т.к. не нужно, т.к. списки (читай данные программы в том числе) не мутабельны - есть только переопределение.
__________________
Когда в руках молоток все вокруг кажется гвоздями.
Дима_ вне форума  
 
Непрочитано 21.11.2012, 18:09
#9
Кулик Алексей aka kpblc
Moderator

LISP, C# (ACAD 200[9,12,13,14])
 
Регистрация: 25.08.2003
С.-Петербург
Сообщений: 40,450


Цитата:
Сообщение от gomer Посмотреть сообщение
>Кулик Алексей aka kpblc, не SUBR, а USUBR
Это уже не ко мне, а к автору ответа ))
__________________
Моя библиотека lisp-функций
---
Обращение ко мне - на "ты".
Все, что сказано - личное мнение.
Кулик Алексей aka kpblc вне форума  
 
Непрочитано 21.11.2012, 18:21
#10
gomer

строю, ломаю
 
Регистрация: 03.04.2008
Украина
Сообщений: 5,515


ну тады продолжаем усугублять

Цитата:
Сообщение от Kirill_Ja Посмотреть сообщение
Чего-то я второй пример не очень понял
Это примерно то ж, что и
Код:
[Выделить все]
 (apply
  (quote (lambda (f lst)
	   (apply (function +) (mapcar (function f) lst))
	 )
  )
  (list
    (lambda (x) (/ 1. (* x x)))
    '(1 2 3)
  )
)
что, в свою очередь как бы
Код:
[Выделить все]
 
(setq foo (lambda (f lst)
	    (apply (function +) (mapcar (function f) lst))
	  )
)


(foo (lambda (x) (/ 1. (* x x)))
     '(1 2 3)
)
gomer вне форума  
 
Непрочитано 21.11.2012, 23:23
#11
VVA

Инженер LISP
 
Регистрация: 11.05.2005
Минск
Сообщений: 6,996


http://lee-mac.com/mapcarlambda.html
http://ru.wikibooks.org/wiki/Лисп/Функции
http://homelisp.ru/help/lisp.html
__________________
Как использовать код на Лиспе читаем здесь
VVA вне форума  
 
Непрочитано 22.11.2012, 01:24
#12
gomer

строю, ломаю
 
Регистрация: 03.04.2008
Украина
Сообщений: 5,515


Сорри за толстый троллинг, но продолжаем парад планет лямбд, собственно все ссылки хороши, но ничему не учат
Решаем задачку которую не могли решить аж! 90 лет http://hijos.ru/2011/02/27/summa-rya...basel-problem/
Код:
[Выделить все]
 (equal
  ;; Базельская задачка
  (/ (* pi pi) 6)			; вот чему равна вся эта хрень внизу

  ((lambda (f lst)			; применяем лямбду как функцию
     (apply (function +) (mapcar (function f) lst))
   )
    (lambda (x) (/ 1. (* x x)))		; применяем лямбду как аргумент функции
    ((lambda (x)
       ;; создаем рекурсивно список натуральных
       ;; чисел от 1 до 10000 с помощью лямбды 
       ((lambda	(f-rec)
	  ;; тут вообще все мрак и вверх тормашками задом наперед
	  (f-rec 1 x)
	)
	 (lambda (i n)
	   (if (<= i n)
	     (cons i
		   (f-rec (1+ i) n)
	     )
	   )
	 )
       )
     )
      10000
    )
  )

  0.0001

)

(equal
  ;;  Без всяких лямбд и рекурсий получаем точность на порядки выше.  Собственно
  ;; это  проблема не лямбды,  а рекурсии,  хотя итерационный метод  имеет свои
  ;; ограничения.
  (/ (* pi pi) 6)
  (progn
    (setq i 0
	  sum 0
    )
    (while (<= i 10e6)
      (setq i	(1+ i)
	    sum	(+ sum (/ 1. (* (float i) (float i))))

      )
    )
  )
  10e-6
)
точнее не решаем, а проверяем
gomer вне форума  
 
Автор темы   Непрочитано 22.11.2012, 08:58
#13
Kirill_Ja


 
Регистрация: 28.07.2008
Мурманск
Сообщений: 208
<phrase 1=


Очень хорошо))) Через Ваш парад уже кое-что понятно. Еще вопрос.
Функция (function). В книге тоже не очень понятно про нее написано. И, судя по примерам, одно без другого не бывает)
Kirill_Ja вне форума  
 
Непрочитано 22.11.2012, 09:16
#14
gomer

строю, ломаю
 
Регистрация: 03.04.2008
Украина
Сообщений: 5,515


Читайте справку хоть иногда, там же все понятно написано
gomer вне форума  
 
Непрочитано 22.11.2012, 09:26
#15
Дима_

Продуман
 
Регистрация: 22.02.2007
Питер
Сообщений: 2,839


То gomer - перестарался с лямбдами - f и lst вобще не нужны (зачем их именовать если они применяется 1 раз в mapcar'е):
Код:
[Выделить все]
 (defun basel()
  ((lambda (ml) (apply '+ (mapcar '(lambda (x) (/ 1.0 (* x x))) (ml 1000))))
   (lambda (x) (if (not (zerop x)) (cons x (ml (1- x)))))))
__________________
Когда в руках молоток все вокруг кажется гвоздями.
Дима_ вне форума  
 
Автор темы   Непрочитано 22.11.2012, 09:32
#16
Kirill_Ja


 
Регистрация: 28.07.2008
Мурманск
Сообщений: 208
<phrase 1=


Все. Понял. Справка великая весчь.

Попробую сам сваять.

Последний раз редактировалось Kirill_Ja, 22.11.2012 в 09:42.
Kirill_Ja вне форума  
 
Непрочитано 22.11.2012, 09:38
#17
Дима_

Продуман
 
Регистрация: 22.02.2007
Питер
Сообщений: 2,839


Примерно так.
Если углубляться то здесь вобще история долгая, в лиспе можно передать функцию как функцию (что по умолчанию используют например в Scheme) или как тело (простое или скомпилированное) - проще говоря список символов - что по умолчанию идет в AutoLisp, CommonLisp... В чем разница? в том что с ней предполагается делать. В Scheme предпологается использование т.н. лексических замыканий (то есть если какое-либо имя используется внутри функции - оно берется на момент ОПРЕДЕЛЕНИЯ это функции), а в автолиспе по барабану что там за имена - к ним обращаются только на момент выполнения - то есть в "голом" виде:
(defun x() (+ a b)) - в автолиспе вполне себе нормальная функция, но запустить (без фатальной ошибки) ее можно только при условии что "внешне" определенны a и b и их можно сложить между собой. В Sheme подобная конструкция не примется на этапе ввода - т.к. при сохранении функции ему необходимо "знать" a и b - если знакомы с ООП - то функция это типа объект, а a и b своего рода "приватные" свойства. Из-за этого в AutoLispe переодически возникает необходимость "обработать" список функции перед выполнением (хотя эта необходимость возникает при использовании определенного стиля программирования, что в общем случае не часто - а чаще используется передача аргументов, а еще чаще (и не правильней) установка "внешних переменных" (точнее говорить переопределение внешних имен), но, в определенных задачах, дает существенные выйгрыши).
p.s. Kirill_Ja не переправляй целиком посты - а то уже не ясно к чему этот - он посвящен quote и function.
__________________
Когда в руках молоток все вокруг кажется гвоздями.

Последний раз редактировалось Дима_, 22.11.2012 в 10:15.
Дима_ вне форума  
 
Непрочитано 22.11.2012, 18:05
#18
gomer

строю, ломаю
 
Регистрация: 03.04.2008
Украина
Сообщений: 5,515


Цитата:
Сообщение от Дима_ Посмотреть сообщение
перестарался с лямбдами - f и lst вобще не нужны (зачем их именовать если они применяется 1 раз в mapcar'е):
для наглядности и вообще, я так старался так старался, такие лямбдочки получились красивенькие а Вы...
Впрочем, эта задача слишком тривиальна для лямбд, так как
Код:
[Выделить все]
 (defun basel (n)
  (if (zerop n)
    0
    (+ (expt n -2.) (basel (1- n)))
  )
)
Собственно как итог:
1. Лямбды применяют как аргумент функций типа mapcar, либо пользовательских
2. Для создания локальных пространств имен возможностью добавления аккумулирующих аргументов
gomer вне форума  
 
Непрочитано 22.11.2012, 18:44
#19
Klo

Инженер-конструктор
 
Регистрация: 29.10.2007
Юбилейный МО
Сообщений: 269


Раз уж у автора есть книжка Полещука (надеюсь AutiLISP в среде AutoCAD), то неплохо бы потрудиться заглянуть на стр. 80 есть понятный пример:
Код:
[Выделить все]
 (vl-sort '((3.2 -1.1) (5.9 6.0) (1.9 1.3)) (function (lambda (e1 e2) (> (car e1) (car e2)))))
Klo вне форума  
 
Автор темы   Непрочитано 27.11.2012, 10:27
#20
Kirill_Ja


 
Регистрация: 28.07.2008
Мурманск
Сообщений: 208
<phrase 1=


Свой пример и моя благодарность, что объяснили.

Код:
[Выделить все]
 

(setq l_f (lambda (qqq) (if (= (car qqq) 10) (cdr qqq))))
(vl-remove nil (mapcar (function l_f) (entget (car (entsel)))))

Выдает базовую точку для объектов и список вершин для LWPolyline

Последний раз редактировалось Kirill_Ja, 27.11.2012 в 15:54.
Kirill_Ja вне форума  
 
Непрочитано 27.11.2012, 11:50
#21
Дима_

Продуман
 
Регистрация: 22.02.2007
Питер
Сообщений: 2,839


1. Зачем вы создали l_f да еще таким извращенным способом (если она и нужна - можно было через defun).
2. ИХМО vl-remove nil идеологически не правильно (потом так-же будешь обрабатывать списки в которых изначально есть nil - забудешь на 300%), то есть вначале фильрация, потом преобразование (в других лиспах есть дефолтные конструкции делающие это одновременно - но ничего не мешает сделать их для себя в автолиспе) - (mapcar 'cdr (vl-remove-if-not '(lambda (x) (= (car x) 10)) (entget (car (entsel)))))
3. У тебя возращает не точку, а список значений по оси X.
4. В полилинии (и не только) полученную точку надо еще преобразовать в мировую систему (попробуй свой лисп на полилинии не в плоскости "сверху") - см. функцию (trans...
__________________
Когда в руках молоток все вокруг кажется гвоздями.
Дима_ вне форума  
 
Непрочитано 27.11.2012, 15:09
#22
gomer

строю, ломаю
 
Регистрация: 03.04.2008
Украина
Сообщений: 5,515


Если честно по 2. ниче не понял. Скажу проще: вместо того чтоб "занилять" ненужные подсписки, а потом удалять их, можно просто удалять их

Последний раз редактировалось gomer, 27.11.2012 в 15:23.
gomer вне форума  
 
Автор темы   Непрочитано 27.11.2012, 16:05
#23
Kirill_Ja


 
Регистрация: 28.07.2008
Мурманск
Сообщений: 208
<phrase 1=


Про фильтрацию впитал. Лисп в посте #20 подправил.

А почему способ извращенный? Дальше этой переменной присваиваются значения. Собственно, в нее уходит список с координатами.

А этот код можно сделать проще

Код:
[Выделить все]
 

(defun coor ( / )

(setq rec (lambda (name / n_a)
    (progn (setq n_a (entget name))  
       (cond
	 ( (= (cdr(assoc 0 n_a)) "VERTEX")
	   (append (list (assoc 10 n_a)) (apply (function rec) (list (entnext name))))
	); end vertex
          ( (= (cdr(assoc 0 n_a)) "SEQEND") '(nil)); end seqend
        ); end cond
     ); end progn
    );end lambda
  ); end setq

(setq rec (apply (function rec) (list (entnext (car (entsel))))))
(setq rec (mapcar 'cdr (vl-remove-if-not '(lambda (x) (= (car x) 10)) rec)))
(mapcar (function (lambda (x) (trans x 1 0))) rec)

); end defun


Это уже для 2д/3д полилиний

Сорри за угребищное описание rec. Она большая и к ней не очень удобно обращаться по описанию.

Последний раз редактировалось Kirill_Ja, 27.11.2012 в 16:40.
Kirill_Ja вне форума  
 
Непрочитано 27.11.2012, 18:03
#24
gomer

строю, ломаю
 
Регистрация: 03.04.2008
Украина
Сообщений: 5,515


сам то понял что написал?
Код:
[Выделить все]
 (defun GET-PLVLIST (EN)
  ((lambda (VLIST DXF) ; вообще эта лямбда тут 100 лет не нужна, но тема такая :)
     (while (/= "SEQEND" (DXF 0 (setq EN (entnext EN))))
       (setq VLIST (append VLIST (list (DXF 10 EN))))
     )
   )
    '()
    (lambda (x y) (cdr (assoc x (entget y))))
  )
)

(GET-PLVLIST (car (entsel)))
gomer вне форума  
 
Автор темы   Непрочитано 27.11.2012, 18:57
#25
Kirill_Ja


 
Регистрация: 28.07.2008
Мурманск
Сообщений: 208
<phrase 1=


Если я пойму как это работает - это будел level up
Kirill_Ja вне форума  
 
Непрочитано 27.11.2012, 20:59
#26
Дима_

Продуман
 
Регистрация: 22.02.2007
Питер
Сообщений: 2,839


Цитата:
Сообщение от gomer Посмотреть сообщение
(append VLIST (list (DXF 10 EN)))
Опять, двадцать пять...
__________________
Когда в руках молоток все вокруг кажется гвоздями.
Дима_ вне форума  
 
Непрочитано 27.11.2012, 22:18
#27
gomer

строю, ломаю
 
Регистрация: 03.04.2008
Украина
Сообщений: 5,515


Цитата:
Сообщение от Дима_ Посмотреть сообщение
Опять, двадцать пять...
мопед не мой...
gomer вне форума  
 
Непрочитано 25.12.2012, 09:03
#28
PDM


 
Регистрация: 25.03.2012
Сообщений: 12


Подробно про "lambda" в книге "Мир Лиспа", Э. Хювенен, том 1.
PDM вне форума  
 
Непрочитано 26.12.2012, 14:13
1 | #29
Елпанов Евгений

программист
 
Регистрация: 20.12.2005
Москва
Сообщений: 1,439
Отправить сообщение для Елпанов Евгений с помощью Skype™


В первую очередь извиняюсь - я не смог заставить себя прочесть всю ветку.

теперь по теме:
для многократного использования кода, имеет смысл создать специальную функцию, которая будет выполнять действие, например:

многократное выполнение a + b*2 можно написать программу:
Код:
[Выделить все]
 (defun f (a b) (+ a b b))
теперь в любом месте можно просто вызвать:
Код:
Это очень простой пример, в более сложных вычислениях, определение дополнительного кода в отдельную функцию действительно оправдано.

Но вернемся к lambda функциям. Допустим нам необходимо много раз выполнить подобную функцию, но только для одного списка. Получается определение самостоятельной функции избыточно. На такой случай, есть возможность создания временной функции, которая будет существовать только в рамках используемого места. Для временной функции не будет создаваться имя и как следствие ее нельзя вызвать еще раз. (обычным образом, но обо всем по порядку )

для нашего примера, можно создать вариант с временной функцией:
Код:
[Выделить все]
 ((lambda(a b)(+ a b b)) 5 6)
в этом случае, временная функция однократно выполнит функционал предыдущей функции, но используя lambda определение функции.

пришло время рассказать о списках - именно здесь и кроется все удобство использования lambda:
используем функцию F для обработки списков.
Код:
[Выделить все]
 (mapcar 'f '(1 2 3) '(4 5 6))
в этом коде, функция обработки списка последовательно подставляет в функцию F элементы из первого и второго списков - аргументов, сначала первые, потом вторые итд. т.е сначала выполняется код (f 1 4) потом (f 2 5) ...

В общем случае, использование в mapcar именованных функций, определенных подобно F, очень удобно. Но в случае, когда для каждого mapcar придется писать собственную функцию со своим определением, поддержка такого кода получается не самой удобной. В одном месте создается функция для обработки списка, а совершенно в другом происходит сама обработка. Для таких случаев и создана lambda. Например:
Код:
[Выделить все]
 (mapcar '(lambda(a b)(+ a b b)) '(1 2 3) '(4 5 6))


ps. как и обещал, поясню о сохранении функции lambda. никто не запрещает сохранить саму lambda функцию в переменную для многократного использования:
Код:
[Выделить все]
 (setq foo (lambda(a b)(+ a b b)))
(mapcar 'foo  '(1 2 3) '(4 5 6))
(mapcar 'foo  '(1 2 3) '(0 0 0))
__________________
Чем гениальнее ваш план, тем меньше людей с ним будут согласны.
/Сунь Цзы/
Елпанов Евгений вне форума  
 
Непрочитано 26.12.2012, 14:30
#30
Дима_

Продуман
 
Регистрация: 22.02.2007
Питер
Сообщений: 2,839


Цитата:
Сообщение от Елпанов Евгений Посмотреть сообщение
ps. как и обещал, поясню о сохранении функции lambda. никто не запрещает сохранить саму lambda функцию в переменную для многократного использования:
Если смотреть с точки зрения лиспа, то тут немного верх ногами - defun - это такая обертка сохраняющая функции в текущей области видимости (что в общем-то не всегда нужно).
__________________
Когда в руках молоток все вокруг кажется гвоздями.
Дима_ вне форума  
 
Непрочитано 26.12.2012, 14:41
#31
Елпанов Евгений

программист
 
Регистрация: 20.12.2005
Москва
Сообщений: 1,439
Отправить сообщение для Елпанов Евгений с помощью Skype™


Цитата:
Сообщение от Дима_ Посмотреть сообщение
Если смотреть с точки зрения лиспа, то тут немного верх ногами - defun - это такая обертка сохраняющая функции в текущей области видимости (что в общем-то не всегда нужно).
Вы правы!

Код:
[Выделить все]
 (mapcar (defun f (a b) (+ a b b)) '(1 2 3) '(4 5 6))
__________________
Чем гениальнее ваш план, тем меньше людей с ним будут согласны.
/Сунь Цзы/
Елпанов Евгений вне форума  
 
Непрочитано 26.12.2012, 19:43
#32
gomer

строю, ломаю
 
Регистрация: 03.04.2008
Украина
Сообщений: 5,515


Цитата:
Сообщение от Дима_ Посмотреть сообщение
defun - это такая обертка сохраняющая функции в текущей области видимости
Цитата:
Сообщение от Елпанов Евгений Посмотреть сообщение
(mapcar (defun f (a b) (+ a b b)) '(1 2 3) '(4 5 6))
В данном случае это документ?

Но, особым извращением я считаю форму (lambda nil ... )
gomer вне форума  
 
Непрочитано 27.12.2012, 11:16
#33
Do$

AutoCAD/Civil3D LISP/C#
 
Регистрация: 15.08.2008
Санкт-Петербург
Сообщений: 1,701
Отправить сообщение для Do$ с помощью Skype™


А почему нет?
Код:
[Выделить все]
(setq sel (vl-catch-all-apply '(lambda nil (entsel "\nВыберите объект:"))))
(if (not (vl-catch-all-error-p sel)) <...>)
Do$ вне форума  
 
Непрочитано 27.12.2012, 11:37
#34
Дима_

Продуман
 
Регистрация: 22.02.2007
Питер
Сообщений: 2,839


nil и '() - это синонимы (можно в любом месте поменять одно на другое - результат не изменится), просто в автолиспе нет как такогого булевского типа (то есть есть, но совмещенно-половинчатый) T или любое значение кроме nil (или '()) и собственно nil - который "по совместительству" пустой список. Кое-где это приносит выгоду:
Код:
[Выделить все]
 (if lst (cons (car lst) ...)
        а здесь ничего не нужно - т.к. вернет пустой список)
то есть мы сэкономили на предикате (null?) проверки и нам не нужно возращать пустой список. Но иногда бывают и излишние сложности когда, например надо что-то отфильровать из "смешанного списка" значений, а там есть как логика так и списки (которые могут быть пустыми). Лично я (для читабельности) использую обозначение nil - там где это подразумеват булевское значение и '() - в случае пустого списка.
__________________
Когда в руках молоток все вокруг кажется гвоздями.
Дима_ вне форума  
 
Непрочитано 27.12.2012, 11:47
#35
Елпанов Евгений

программист
 
Регистрация: 20.12.2005
Москва
Сообщений: 1,439
Отправить сообщение для Елпанов Евгений с помощью Skype™


Цитата:
Сообщение от Do$ Посмотреть сообщение
(setq sel (vl-catch-all-apply '(lambda nil (entsel "\nВыберите объект:"))))
(if (not (vl-catch-all-error-p sel)) <...>)
ничем не отличается от:
Код:
[Выделить все]
 (if (setq sel (entsel "\nВыберите объект:")) <...>)
__________________
Чем гениальнее ваш план, тем меньше людей с ним будут согласны.
/Сунь Цзы/
Елпанов Евгений вне форума  
 
Непрочитано 27.12.2012, 11:59
#36
Дима_

Продуман
 
Регистрация: 22.02.2007
Питер
Сообщений: 2,839


Цитата:
Сообщение от Елпанов Евгений Посмотреть сообщение
ничем не отличается от:
обработает esc...
__________________
Когда в руках молоток все вокруг кажется гвоздями.
Дима_ вне форума  
 
Непрочитано 27.12.2012, 16:13
#37
gomer

строю, ломаю
 
Регистрация: 03.04.2008
Украина
Сообщений: 5,515


Цитата:
Сообщение от Do$ Посмотреть сообщение
А почему нет?
в данном случае можно кетчить entsel, а не лямбду, впрочем я ж не против, просто по логике у функции должен быть хотя б один аргумент
gomer вне форума  
 
Непрочитано 27.12.2012, 16:28
#38
Кулик Алексей aka kpblc
Moderator

LISP, C# (ACAD 200[9,12,13,14])
 
Регистрация: 25.08.2003
С.-Петербург
Сообщений: 40,450


Цитата:
Сообщение от gomer Посмотреть сообщение
по логике у функции должен быть хотя б один аргумент
ИМХО далеко не обязательно
__________________
Моя библиотека lisp-функций
---
Обращение ко мне - на "ты".
Все, что сказано - личное мнение.
Кулик Алексей aka kpblc вне форума  
 
Непрочитано 27.12.2012, 17:30
#39
Do$

AutoCAD/Civil3D LISP/C#
 
Регистрация: 15.08.2008
Санкт-Петербург
Сообщений: 1,701
Отправить сообщение для Do$ с помощью Skype™


Цитата:
Сообщение от gomer Посмотреть сообщение
в данном случае можно кетчить entsel, а не лямбду
Ну это простой слишком пример
Вот тут уже не так просто:
Код:
[Выделить все]
(setq pt (vl-catch-all-apply '(lambda nil (initget 1) (getpoint "\nУкажите точку:"))))
В общем-то, это все до боли знакомо, если приходилось использовать функцию
Do$ вне форума  
 
Непрочитано 27.12.2012, 17:39
#40
gomer

строю, ломаю
 
Регистрация: 03.04.2008
Украина
Сообщений: 5,515


Цитата:
Сообщение от Do$ Посмотреть сообщение
Вот тут уже не так просто:
переняся initget на строчку выше, приходим к исходной конструкции
а насчет каскадов ловушек с лямбдами, лучше написать свой нормальный *error*

Последний раз редактировалось gomer, 27.12.2012 в 17:48.
gomer вне форума  
 
Непрочитано 27.12.2012, 20:00
#41
ShaggyDoc

Thượng Tá Quân Đội Nhân Dân Việt Nam
 
Регистрация: 14.03.2005
44d32'44"С, 33d26'51"В
Сообщений: 13,372


Цитата:
лучше написать свой нормальный *error*
Ну, попробуй напиши. Такую *error*, чтобы перехватывала ESC. Функция *error* срабатывает, когда уже "поздно пить боржоми". Т.е. когда ошибку уже не предотвратить, программа уже вылетает. Причем независимо от того, на каком уровне вложенных функций произошел вылет. Здесь можно только что-то мявкнуть, да что-то восстановить.

ESC для AutoLISP - "лом, против которого нет приема".

А ловушки ошибок действуют наподобие try... except ... end. vl-catch-all-ххх - наилучшая новинка в LISP за последние 10 лет. С их помощью можно предотвратить любую ошибку на любом уровне вложения.
ShaggyDoc вне форума  
 
Непрочитано 27.12.2012, 21:53
#42
gomer

строю, ломаю
 
Регистрация: 03.04.2008
Украина
Сообщений: 5,515


Цитата:
Сообщение от ShaggyDoc Посмотреть сообщение
А ловушки ошибок действуют наподобие try... except ... end. vl-catch-all-ххх - наилучшая новинка в LISP за последние 10 лет.
Согласен, вот только такие ловушки напоминают комивояжера, который пока не продаст, не отстанет.
Цитата:
Сообщение от ShaggyDoc Посмотреть сообщение
ESC для AutoLISP - "лом, против которого нет приема".
ну это логично. Нажимаешь ты отмену, а тебе программа так ехидно
Цитата:
А может, все же, на балет?
С другой стороны, если программе не хватает данных, она правильно работать дальше не будет.
К тому же vl-catch-all-apply по барабану на ошибки command, например, при вставке блока
gomer вне форума  
 
Непрочитано 27.12.2012, 22:19
#43
ShaggyDoc

Thượng Tá Quân Đội Nhân Dân Việt Nam
 
Регистрация: 14.03.2005
44d32'44"С, 33d26'51"В
Сообщений: 13,372


Цитата:
Нажимаешь ты отмену, а тебе программа так ехидно
А это уже зависит от того, как автор напишет. Где-то можно разрешить, где-то нельзя. Об ошибках можно сообщать, а можно и не сообщать.
Цитата:
если программе не хватает данных, она правильно работать дальше не будет
Опять же зависит от программиста.

Цитата:
К тому же vl-catch-all-apply по барабану на ошибки command, например, при вставке блока
И это зависит от программиста. Исключительно. Применяется не одна функция, а связка из них, чтобы появился как бы try... except ...end, только на Lisp
ShaggyDoc вне форума  
 
Непрочитано 28.12.2012, 02:31
#44
gomer

строю, ломаю
 
Регистрация: 03.04.2008
Украина
Сообщений: 5,515


Цитата:
Сообщение от ShaggyDoc Посмотреть сообщение
Опять же зависит от программиста.
если для вставки блока нужна точка масштаб и угол поворота, то без них блок вставить нельзя, не выдумывать же, это не правильно, более того, vl-catch-all-apply эту ситуацию не отловит, потому что command своя логика, да и вообще она с command работать не хочет, только с лямбдой
для примера
(vl-catch-all-apply '(lambda nil (command "_.insert" "d:\\test" pause 1 1 pause))) - ошибка при нажатии еск во время выбора угла поворота ловится
(vl-catch-all-apply '(lambda nil (command "_.insert" "d:\\test" pause))) - ошибка при нажатии еск во время выбора угла поворота не ловится
(vl-catch-all-apply 'command (list "_.insert" pause "d:\\test" pause 1 1 pause)) - ; ошибка: неверная порядковая функция: COMMAND
так что vl-catch-all-apply - не панацея
gomer вне форума  
 
Непрочитано 28.12.2012, 08:24
#45
ShaggyDoc

Thượng Tá Quân Đội Nhân Dân Việt Nam
 
Регистрация: 14.03.2005
44d32'44"С, 33d26'51"В
Сообщений: 13,372


Цитата:
vl-catch-all-apply - не панацея
Читай ещё раз:
Цитата:
Применяется не одна функция, а связка из них, чтобы появился как бы try... except ...end, только на Lisp
Эту связку я не раз приводил в пример.
Цитата:
(vl-catch-all-apply '(lambda nil (command "_.insert" "d:\\test" pause))) - ошибка при нажатии еск во время выбора угла поворота не ловится
Читай ещё раз:
Цитата:
А это уже зависит от того, как автор напишет...Опять же зависит от программиста
Всегда можно умудриться написать так, что работать не будет. Ловушки ставятся для ситуаций времени выполнения, а не для ловли ошибок в коде.

Однако, раз тема про lambda, приведу пример использования как раз в ловушке ошибок.
Сначала напишем саму функцию-ловушку.

Код:
[Выделить все]
 
(defun ru-error-catch (protected_expression on_error_expression / catch_error_result)
  (setq catch_error_result (vl-catch-all-apply protected_expression)) 
  (if (and (vl-catch-all-error-p catch_error_result) on_error_expression)
    (apply on_error_expression (list (vl-catch-all-error-message catch_error_result))) 
    catch_error_result
  )
)
Обратите внимание - используются три функции семейства vl-catch-all-

Как надо вызывать - схема:
Код:
[Выделить все]
 
(ru-error-catch
     ;;; Аналог try в других языках
    (function (lambda ()
                ;;; защищаемое выражение  , которое надо попробовать
                (
                
                )
                ;;; То что вернет - будет результатом
              ) 
    ) 
     ;;; Аналог  except  в других языках
	 ;;; что делать, если произошла ошибка
    (function
      (lambda (err_msg)
        ;; если надо - выводим сообщение. err_msg подставит Автокад
        (princ (strcat "\nОШИБКА такой-то функции: " err_msg))
        ;; возвращаем NIL при ошибке
        nil
      ) 
    )   
)

Обратите внимание - два раза используется lambda.

Конечно, "простому инженеру" (прикладному программисту), который механизирует свои типовые задачи, наподобие вставок блоков, с этим трудновато разобраться. Для упрощения работы прикладных программистов создаются библиотеки низкоуровневых функций, в которых спрятаны все сложности. А в конкретной программе (функции, конечно), навешиваемой "на кнопку", надо применять простые высокоуровневые функции. Надежные. Чтобы не писали муру наподобие (command "_.insert" "d:\\test" pause 1 1 pause) только потому что так проще.

Если уж упомянули блоки, то каждому надо вставлять, например, блоки условных обозначений. Причем надо, чтобы вставка блочишки была многократная, в цикле. Чтобы при этом блок "висел" на курсоре. Чтобы можно было задать поворот или не задавать. Чтобы блок ещё и масштабировался правильно. Чтобы могли быть атрибуты, а могли и не быть. И чтобы это можно было легко применить. Чтобы на уровне меню можно было написать:

Сантехнику: (ru-block-insert-from-lib "sanitary\\ru-lib-abok-schem-free-valves-ind" "abok_2_8_05_F-03" 1 1 1 nil))
Топографу: (ru-block-insert-from-lib "land\\ru-lib-topo" "ru_topo_0139" 1 1 1 T))
Строителю: (ru-block-insert-from-lib "common\\ru-lib-common" "number_door_ru" 1 1 1 T))

Здесь применяется библиотечная функция ru-block-insert-from-lib, которая объявлена так
(ru-block-insert-from-lib block_lib_name block_name ins_code x_scale y_scale is_angle0)
Она делает множественную вставку блока с заданными параметрами из библиотеки блоков. Эту функцию здесь не привожу для экономии места. Она внедряет в чертеж блок из библиотеки, вычисляет масштабы вставки и вызывает низкоуровневую функцию _ru-block-multi-insert-scaled-rotated-or-angleask с подготовленными параметрами. Вот её-то и покажу
Код:
[Выделить все]
 
(defun _ru-block-multi-insert-scaled-rotated-or-angleask 
(block_name  x_scale y_scale block_angle msg_insert msg_angle /   
old_attdia old_attreq  result is_angle_ok is_point_ok  do)
 (setq old_attdia (getvar "ATTDIA") old_attreq(getvar "ATTREQ")  do t)
 (setvar "ATTDIA" 0)
 (setvar "ATTREQ" 0)
 (ru-var-clear-insunit)
 (while do
  (ru-error-catch
   (function (lambda ()
              (princ (strcat "\n" msg_insert " или ESC для выхода: "))
              (setq is_point_ok
                    (vl-cmdf "_.INSERT"
                             block_name
                             "_PROTATE"
                             (if block_angle
                              block_angle
                              0
                             )
                             "_PXScale"
                             x_scale
                             "_PYScale"
                             y_scale
                             pause
                    )
              )
              (if is_point_ok
               (progn
                (vl-cmdf
                 x_scale
                 y_scale
                 (if (not block_angle)
                  (progn  (princ "\nУгол поворота <0>: ") pause)
                  block_angle
                 )
                )
                (ru-block-dlg-attedit (entlast))
               )
              )
              (setq do is_point_ok)
             )
   ) 
   nil
  ) 
 ) 
 (ru-var-restore-insunit)
 (setvar "ATTDIA"  old_attdia)
 (setvar "ATTREQ"  old_attreq)
 (princ)
)
Тут и ловушка ошибок есть, и обработка ESC - специально для прерывания цикла, но не для прерывания программы. Ну и lambda - тема ветки.
ShaggyDoc вне форума  
 
Непрочитано 28.12.2012, 09:01
#46
Кулик Алексей aka kpblc
Moderator

LISP, C# (ACAD 200[9,12,13,14])
 
Регистрация: 25.08.2003
С.-Петербург
Сообщений: 40,450


Касательно отлова ошибок - в свое время я пришел в выводу, что *error* лучше не переопределять (причины, в частности, рассматривал тут). Особенно при работе в вертикальных приложениях.
__________________
Моя библиотека lisp-функций
---
Обращение ко мне - на "ты".
Все, что сказано - личное мнение.
Кулик Алексей aka kpblc вне форума  
 
Непрочитано 31.12.2012, 11:14
#47
G-RAV

Геодезист
 
Регистрация: 16.08.2009
г.Новосибирск
Сообщений: 86
<phrase 1=


Объясните, пожалуйста, как с помощью Lambda получить максимальные и минимальные значения списка, т.е. есть список, например:
Код:
[Выделить все]
((22 12) (1 34) (56 -32) (0 12) (-4 12))
, а получить необходимо минимальное
Код:
максимальное
Код:
. С Foreach разобрался, а вот Lambda не поддается).
G-RAV вне форума  
 
Непрочитано 31.12.2012, 12:47
#48
Дима_

Продуман
 
Регистрация: 22.02.2007
Питер
Сообщений: 2,839


Ну с помощью голой лямбда наверное никак, тебе непонятно как алгоритм реализовать, или алгоритм понятен но не получается выразить его через лямбда выражения?
__________________
Когда в руках молоток все вокруг кажется гвоздями.
Дима_ вне форума  
 
Непрочитано 31.12.2012, 12:53
#49
G-RAV

Геодезист
 
Регистрация: 16.08.2009
г.Новосибирск
Сообщений: 86
<phrase 1=


Через Лямбда не получается, а хотелось бы...
Через Foreach получилось как то вот так:
Код:
[Выделить все]
(foreach x myLIST
    (cond
    ((< (car x) Xmin) (setq Xmin (car x)))
    ((> (car x) Xmax) (setq Xmax (car x)))
    )
    (cond    
    ((< (cadr x) Ymin) (setq Ymin (cadr x)))
    ((> (cadr x) Ymax) (setq Ymax (cadr x)))
    )
  )
Наверное стоит добавить, что перед кодом стоит:
Код:
[Выделить все]
(SETQ Xmin (caar myLIST) Ymin (cadar myLIST) Xmax Xmin Ymax Ymin)

Последний раз редактировалось G-RAV, 02.01.2013 в 16:09.
G-RAV вне форума  
 
Непрочитано 31.12.2012, 15:13
1 | #50
Кулик Алексей aka kpblc
Moderator

LISP, C# (ACAD 200[9,12,13,14])
 
Регистрация: 25.08.2003
С.-Петербург
Сообщений: 40,450


Код:
[Выделить все]
 (setq lst '((22 12) (1 34) (56 -32) (0 12) (-4 12)))
(mapcar (function (lambda (f)
                    (apply (function min)
                           (mapcar
                             (function (lambda (x) (f x)))
                             lst
                             ) ;_ end of mapcar
                           ) ;_ end of apply
                    ) ;_ end of lambda
                  ) ;_ end of function
        (list car cadr)
        ) ;_ end of mapcar
__________________
Моя библиотека lisp-функций
---
Обращение ко мне - на "ты".
Все, что сказано - личное мнение.
Кулик Алексей aka kpblc вне форума  
 
Непрочитано 31.12.2012, 17:55
1 | #51
gomer

строю, ломаю
 
Регистрация: 03.04.2008
Украина
Сообщений: 5,515


Сначала не понял, но потом понял, что думаю о том же. Мой вариант попроще:
Код:
[Выделить все]
 ((lambda (fpar lst)
   (mapcar
     (function
       (lambda (f)
	 (apply fpar (mapcar f lst))
       )
     )
     '(car cadr)
   )
 )
  'min
  '((22 12) (1 34) (56 -32) (0 12) (-4 12))
)
Вариант с foreach, но проще

Код:
[Выделить все]
 ((lambda (f lst / result)
   (setq result (car lst))
   (foreach x lst
     (setq result
	    (list
	      (f (car  result) (car  x))
	      (f (cadr result) (cadr x))
	    )
     )
   )
 )
  min
  '((22 12) (1 34) (56 -32) (0 12) (-4 12))
)

Последний раз редактировалось gomer, 31.12.2012 в 18:57.
gomer вне форума  
 
Непрочитано 02.01.2013, 17:13
#52
G-RAV

Геодезист
 
Регистрация: 16.08.2009
г.Новосибирск
Сообщений: 86
<phrase 1=


Большое спасибо за варианты. С последним разобрался, а вот с первым….
gomer, правильно ли я понял первый вариант? Все первые элементы подсписков объединяются в один список
Код:
[Выделить все]
(22 1 56 0 -4)
, все вторые элементы объединяются во второй список
Код:
[Выделить все]
(12 34 -32 12 12)
и уже в этих списках поиск минимальных значений?
G-RAV вне форума  
 
Непрочитано 02.01.2013, 20:37
#53
gomer

строю, ломаю
 
Регистрация: 03.04.2008
Украина
Сообщений: 5,515


Цитата:
Сообщение от G-RAV Посмотреть сообщение
Все первые элементы подсписков объединяются в один список
Цитата:
Сообщение от G-RAV Посмотреть сообщение
все вторые элементы объединяются во второй список
Цитата:
Сообщение от G-RAV Посмотреть сообщение
и уже в этих списках поиск минимальных значений?
да, собственно первый вариант, проистекает из второго в два действия, важно понять, что точка отсчета функции - содание списка (list), просто mapcar это делает неявно, причем шиворот-навыворот
gomer вне форума  
 
Непрочитано 09.01.2013, 16:10
#54
G-RAV

Геодезист
 
Регистрация: 16.08.2009
г.Новосибирск
Сообщений: 86
<phrase 1=


А вот в этом случае, можно еще оптимальнее?
Код:
[Выделить все]
  ((lambda (str / rs)
(setq rs t i 0)
(foreach x (vl-string->list str)
(cond
((and(<= x 57)(>= x 48))t)
((and(= x 46)(= i 0))(setq i (1+ i)))
(t(setq rs nil))
))rs
)
"текст")
Проверяет является ли содержимое строки положительным числом (целым или вещественным) с точкой в качестве разделителя, если нет возвращает nil, если да t.
G-RAV вне форума  
 
Непрочитано 09.01.2013, 16:58
#55
Дима_

Продуман
 
Регистрация: 22.02.2007
Питер
Сообщений: 2,839


Цитата:
Сообщение от G-RAV Посмотреть сообщение
можно еще оптимальнее
У Вас идет проверка всего списка - а достоточно закончить на первом неверном.
__________________
Когда в руках молоток все вокруг кажется гвоздями.
Дима_ вне форума  
 
Непрочитано 09.01.2013, 16:58
#56
TararykovDG

Программист-энтузиаст
 
Регистрация: 17.07.2009
Воронеж
Сообщений: 575


Цитата:
Сообщение от G-RAV Посмотреть сообщение
А вот в этом случае, можно еще оптимальнее?
А при чем тут lambda?

На тему
Цитата:
Сообщение от G-RAV Посмотреть сообщение
Проверяет является ли содержимое строки положительным числом (целым или вещественным) с точкой в качестве разделителя, если нет возвращает nil, если да t.
{Конкурс} Lisp. Пребразование в число при возможности
__________________
cadtools
TararykovDG вне форума  
 
Непрочитано 09.01.2013, 17:08
#57
G-RAV

Геодезист
 
Регистрация: 16.08.2009
г.Новосибирск
Сообщений: 86
<phrase 1=


Цитата:
Сообщение от Дима_ Посмотреть сообщение
У Вас идет проверка всего списка - а достоточно закончить на первом неверном.
Спасибо.. Попробую додумать...

Цитата:
Сообщение от TararykovDG Посмотреть сообщение
А при чем тут lambda?
Дык.. а тема как называется? Разбераемся ж с lambda, а #54 просто в качестве примера..
За ссылку спасибо..
G-RAV вне форума  
 
Непрочитано 11.01.2013, 13:07
1 | #58
Елпанов Евгений

программист
 
Регистрация: 20.12.2005
Москва
Сообщений: 1,439
Отправить сообщение для Елпанов Евгений с помощью Skype™


а я, для поиска минимального списка использую другую конструкцию:

Код:
[Выделить все]
 (setq l '((22 12) (1 34) (56 -32) (0 12) (-4 12)))
(apply (function mapcar) (cons (function min) l))
Правда в этой конструкции, лямбда только подразумевается...
__________________
Чем гениальнее ваш план, тем меньше людей с ним будут согласны.
/Сунь Цзы/
Елпанов Евгений вне форума  
 
Непрочитано 11.01.2013, 20:32
#59
gomer

строю, ломаю
 
Регистрация: 03.04.2008
Украина
Сообщений: 5,515


Цитата:
Сообщение от Елпанов Евгений Посмотреть сообщение
а я, для поиска минимального списка использую другую конструкцию:
однако следует помнить это
gomer вне форума  
Ответ
Вернуться   Форум DWG.RU > Программное обеспечение > Программирование > lambda функция объясните понятно.



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Научите лиспу на примере (или как kpblc, VVA и компания пытаются обучить чайника лиспу) Red Nova LISP 5025 20.08.2025 22:52
Выравнивание полилинии в одну линию. f0lk Программирование 50 13.03.2025 14:04
Растягивание Mtext по контуру замкнутой области PlayKid Программирование 7 27.08.2009 13:41
структурированный список Holon Программирование 22 11.09.2007 14:09