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

Вернуться   Форум DWG.RU > Программное обеспечение > Программирование > LISP > LISP - оптимизация кода

LISP - оптимизация кода

Ответ
Поиск в этой теме
Непрочитано 31.07.2004, 21:47 #1
LISP - оптимизация кода
Torino
 
Штаб
Регистрация: 21.08.2003
Сообщений: 943

Написал программу. Идея у нее простая: задаем базовую отметку, приращение высоты. И щелкая по полилиниям меняем их elevations на базовую+приращение. Потом: базовую+2приращения. И т.д.
Хотел спросить знатоков Лиспа: каим образом можно сократить код?
Вот сам код:

Код:
[Выделить все]
(defun Andy_ChElev (/ temp andy_hEntity)
  (vl-load-com)
  (if (= andy_Elev nil)
    (setq andy_Elev 0))
  (if (= andy_Delta nil)
    (setq andy_Delta 0))
  
  (terpri)
  (if (/= (setq temp (getreal (strcat "Введите превышение <" (rtos andy_Elev) ">: "))) nil)
    (setq andy_Elev temp))
  (if (/= (setq temp (getreal (strcat "Введите шаг <" (rtos andy_Delta) ">: "))) nil)
    (setq andy_Delta temp))
  
  (while (/= (setq andy_Entity (entsel (strcat "Выберите объект (либо пустой ввод для установки новых значений): ОТМЕТКА=" (rtos andy_Elev) ", ШАГ=" (rtos andy_Delta)))) nil)
    (setq andy_hEntity (vlax-ename->vla-object (car andy_Entity)))

    (if (/= (vla-put-elevation andy_hEntity andy_Elev) nil)
      (progn
	(print "При изменении превышения возникла ошибка...")
	(exit)
	)
      )

    (if (/= (vla-put-color andy_hEntity 1) nil)
      (progn
	(print "При изменении цвета возникла ошибка...")
	(exit)
	)
      )
    (vla-update andy_hEntity)

    (setq andy_Elev (+ andy_Elev andy_Delta))
    (terpri)
    )
  (Andy_ChElev)
  )

(defun *error* (msg)
  (princ "\n>>>Программа прервана либо пользователем, либо из-за ошибки...")
  (princ "\n>>>Внимание! Эту программу можно применять только к полилиниям и штриховкам...")
  (princ)
  )

(princ "\n>>>Кочетков А.В.")
(princ "\n>>>Для запуска наберите (Andy_ChElev).")
(princ "\n>>>Для выхода из программы нажмите ESC.")
Просмотров: 2586
 
Непрочитано 31.07.2004, 23:49
#2
vk

сисадмин
 
Регистрация: 26.08.2003
Самара
Сообщений: 1,022
<phrase 1=


Не вникая в сам алгоритм работы программы:
1. Функция *error* переопределена. Это хорошо. Плохо то что это переопределение является глобальным. Если так сделать в нескольких программах и загрузить их одну за другой - то реальной функцией *error* будет та, которая загружена последней. Чтоб не париться с восстановлением - можно энтот *error* просто локализовать. Например, так:
Код:
[Выделить все]
(defun Andy_ChElev (/ *error* temp andy_hEntity)
   (defun *error* (msg) 
   ....
   ) ;end of *error* 
   ....сама прога....
) ; end of Andy_ChElev
2.
Цитата:
(/= (какая то функция) nil)
В Лиспе есть целых две функции для проверки на nil. Это (not) и (null). Вторая как то более логична, хотя обе одинаково действуют в данном случае.

3. Наверно луччше всеж проверить выбранный примитив перед его модификацией. А заодно и слой (на блокировку), на котором он размещен... Чтоб прога не вылетала. Впрочем, дело хозяйское.
Как другой вариант решения этой проблемы - функция (vl-catch-all-apply). Если даже не удалось выполнить недозволенное - прога не вылетит. А проверку на "не удалось" можно сделать функцией (vl-catch-all-error-p) и просто выводить сообщение через (princ) или (alert). Последнее действует отрезвляюще и пробуждающе

Так что, похоже, не сокращать, а добавлять еще придется. :wink:
vk вне форума  
 
Непрочитано 01.08.2004, 00:50
#3
Alaspher


 
Сообщений: n/a


Всё, что написал vk, кроме полезности переопределения *error* - совершенно правильно. Переопределение *error*, в этой ситуации - приносит только вред (про это, как раз, всё - точно). Прежде, чем её переопределять, надо задуматься - а какие задачи она будет решать, ну и делать это надо правильно. Кроме того, забудте про существование exit/quit - облегчите жизнь себе и коллегам.

Код, в первом приближении, может быть, примерно, таким (очень наскоро):
Код:
[Выделить все]
(defun c:andy_chelev (/ temp andy_hentity doc lays andy_entity err1 err2 lay lock)
    (if (not (numberp andy_elev))
        (setq andy_elev 0)
    ) ;_ end of if
    (if (not (numberp andy_delta))
        (setq andy_delta 0)
    ) ;_ end of if
    (setq doc  (vla-get-activedocument (vlax-get-acad-object))
          lays (vla-get-layers doc)
    ) ;_ end of setq
    (if (setq temp (getdist (strcat "\nВведите превышение <" (rtos andy_elev) ">: ")))
        (setq andy_elev temp)
    ) ;_ end of if
    (if (setq temp (getdist (strcat "\nВведите шаг <" (rtos andy_delta) ">: ")))
        (setq andy_delta temp)
    ) ;_ end of if
    (while (and (not (vl-catch-all-error-p err1))
                (not (vl-catch-all-error-p err2))
                (setq andy_entity
                         (entsel
                             (strcat
                                 "\nВыберите объект (либо пустой ввод для выхода): ОТМЕТКА="
                                 (rtos andy_elev)
                                 ", ШАГ="
                                 (rtos andy_delta)
                             ) ;_ end of strcat
                         ) ;_ end of entsel
                ) ;_ end of setq
           ) ;_ end of and
        (setq andy_hentity (vlax-ename->vla-object (car andy_entity))
              lay          (vla-item lays (vla-get-layer andy_hentity))
        ) ;_ end of setq
        (if (= (setq lock (vla-get-lock lay)) :vlax-true)
            (vla-put-lock lay :vlax-false)
        ) ;_ end of if
        (setq err1 (vl-catch-all-apply 'vla-put-elevation (list andy_hentity andy_elev))
              err2 (vl-catch-all-apply 'vla-put-color (list andy_hentity 1))
        ) ;_ end of setq
        (vla-update andy_hentity)
        (if (= lock :vlax-true)
            (vla-put-lock lay :vlax-true)
        ) ;_ end of if
        (setq andy_elev (+ andy_elev andy_delta))
    ) ;_ end of while
    (if (vl-catch-all-error-p err1)
        (alert (vl-catch-all-error-message err1))
    ) ;_ end of if
    (if (vl-catch-all-error-p err2)
        (alert (vl-catch-all-error-message err2))
    ) ;_ end of if
    (princ)
) ;_ end of defun
(vl-load-com)
 
 
Непрочитано 01.08.2004, 05:32
#4
BigBrother

Design & programming :)
 
Регистрация: 14.02.2004
Новосибирск
Сообщений: 172
<phrase 1= Отправить сообщение для BigBrother с помощью Skype™


Сократить код в реальных приложениях, считаю можно только использованием библиотечных функций.
Хороший тон - проверка входных значений, сохранение введенных данных для последующего использования в качестве умолчаний.
Библиотечные функции, также хорошо делать не зависящими от типа входных значений, (примитив, список... ) в разумных пределах конечно же. Обязательно также корректное восстановление переменных среды при error / завершении работы.
Alert - имеет смысл выводить _только_ уж при совсем бредовых действиях пользователя. Либо перед действиями которые нельзя отменить. Alert - для теток.

По поводу *error*. Лучше использовать свой обработчик ошибок. Переопределять ее локально имеет смысл, только если необходимо выполнить действия, которых нет в своем.

P.S. Неплохая библиотека Stdlib. http://xarch.tu-graz.ac.at/autocad/stdlib/
BigBrother вне форума  
 
Непрочитано 01.08.2004, 20:10
#5
vk

сисадмин
 
Регистрация: 26.08.2003
Самара
Сообщений: 1,022
<phrase 1=


Вот споры то... Переопределять *error* или нет....

Считаю что в данном случае в своем *error* следует прикрыть АКАДовское сообщение о прерывании функции по Esc и сделать тихий выход. Это первое.
Второе - если возникнет желание реализовать группы для UNDO - то возможно, придется в *error* также сделать и откат.

Все это применительно к конкретной данной ситуации (код в первом постинге - рекурсивный вызов без условий для выхода). Во многих реальных случаях переопределение действительно не нужно.
vk вне форума  
 
Непрочитано 02.08.2004, 07:16
#6
ShaggyDoc


 
Сообщений: n/a


По обработке ошибок см.
http://www.kurganobl.ru/cad/book.jsp...=357&tn=main#b - в контексте окружающих материалов.

Реализация обработчиков ошибок см. http://www.kurganobl.ru/cad/book.jsp...=726&tn=main#b

Особенно интересно использование ловушки ошибок ru-error-catch в сочетании как с методами ActiveX, так и с vl-cmdf.


Реализации в функциях ввода данных см. http://www.kurganobl.ru/cad/book.jsp...nt=116&tn=main При их системном использовании обращение к *error* практически не происходит

Все это в комплексе позволяет предотвратить подавляющую часть ошибок в программах, позникающих при "неправильных" действиях "неправильных" пользователей. Алгоритмические ошибки, конечно не предотвращаются, хотя иногда могут быть отловлены и сбои, вызванные неверным алгоритмом.
 
 
Автор темы   Непрочитано 02.08.2004, 12:30
#7
Torino


 
Регистрация: 21.08.2003
Штаб
Сообщений: 943
<phrase 1=


Всем спасибо за обсуждение, но вопрос в другом:
несколько раз бывало предлагали свои коды начинающие программисты (типа меня) и люди типа Эдуарда, Fantomas'a, kos'a, vk и др.
У вторых код был лаконичнее и красивше.
Поэтому переформулирую вопрос свой так: какие места в Лисп-программе можно переписать с меньшим количеством строк.
Может быть применить несколько другой алгоритм.
Другие функции.

Ведь начинающие как работают: надо выполнить то-то. Для этого можно использовать вот ту функцию в сочетании с вон той.
И не знают, что для выполнения данного действия уже существует функция. Работающая быстрее и стабильнее. Вот в чем вопрос.
Torino вне форума  
 
Непрочитано 02.08.2004, 14:17
#8


 
Сообщений: n/a


Цитата:
Сообщение от Torino
Поэтому переформулирую вопрос свой так: какие места в Лисп-программе можно переписать с меньшим количеством строк.
Меньшее количество строк - не главное. Например, можно не писать "строку" с (initget 1), но получить ненадежную функцию, ломающуюся, если пользователь не ввел данные.

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

В общем плане для улучшения красоты кода надо копать mapcar, lambda и т.п.

Цитата:
..И не знают, что для выполнения данного действия уже существует функция. Работающая быстрее и стабильнее. Вот в чем вопрос.
Так функции надо изучать (как писатель изучает слова, народные выражения и т.п.). Их и стандартных множество, особенно для ActiveX (практически недокументированных). Да еще свои приходится делать.

Приведенный в первоначальном вопросе код Alaspher оптимизировал, но "строк" стало больше. Однако они намного надежнее. Это же можно написать короче, используя, например функции ru-xxx (ссылки давал в темах рядом) для выбора примитива (в функции будет спрятаны проверки на ошибку выбора, тип примитива, блокировку слоя), ввод дистанций и модификацию примитива. Вот тогда будет и просто, и надежно. Да еще, если выявится ошибка в библиотечной функции, можно будет исправить только одно место, не корректируя множество программ.

Alaspher об этих функциях знает, но он использовал только стандартные, чтобы было понятно всем. Что еще можно с этим кодом сделать неясно, так как неясна конечная цель. Это ведь не изменение выдавливания, а что-то другое. Например, построение рельефа. Может быть все в принципе не так можно сделать.
 
Ответ
Вернуться   Форум DWG.RU > Программное обеспечение > Программирование > LISP > LISP - оптимизация кода

Размещение рекламы
Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск