43 / 15 / 2
Регистрация: 27.02.2016
Сообщений: 36
1

Некорректные аргументы функции принимаемой в качестве параметра

27.09.2016, 09:16. Показов 664. Ответов 6
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Допустим есть функция для определения предела последовательности.

Lisp
1
2
3
4
5
6
7
8
9
(defun lim (fn e)
   (do ((i 1 (+ i 1)))
      ((or (< (abs (- (funcall fn i)
                      (funcall fn (+ 1 i))))
              e)
       (< 100000 (funcall fn (+ 1 i))))
      (if (< 100000 (funcall fn (+ 1 i)))
          nil
         (* 1.0 (funcall fn (+ 1 i)))))))
Если последовательность сходится возвращает приближённое значение предела с заданной точностью.

Lisp
1
2
CL-USER> (lim #'(lambda(n)(/ 1 n)) 0.0001)
0.00990099
Если расходится - nil

Lisp
1
2
CL-USER> (lim #'(lambda(n)(* n n)) 0.0001)
NIL
Но если вызов функции выглядит как-нибудь так:

Lisp
1
(lim #'(lambda(n)(/ n (- 5 n))) 0.00001)
То получаем деление на ноль и ошибку.

Как заставить lim фильтровать подобные аргументы принимаемой в качестве аргумента последовательности?
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
27.09.2016, 09:16
Ответы с готовыми решениями:

Отправка функции в качестве параметра
Есть код на vb6, который работает как должен: Public Declare Function xxx Lib &quot;user32&quot; Alias...

Передача функции в качестве параметра
Может кто помочь объяснить следующую часть кода: double MyMethod(Func&lt;double, double&gt; f,...

Передача функции в качестве параметра
#include &lt;iostream&gt; #include &lt;math.h&gt; using namespace std; double f(double x) { return...

Передача функции в качестве параметра
Есть функция которая генерирует строковые переменные и записывает их в файл. В файл они должны...

6
Модератор
Эксперт функциональных языков программированияЭксперт Python
36578 / 20308 / 4218
Регистрация: 12.02.2012
Сообщений: 33,607
Записей в блоге: 13
27.09.2016, 11:42 2
Тут скорее не фильтровать надо, а просто перехватывать возможные ошибки. Для этого есть механизмы. В HomeLisp - это конструкция (try ... except ...):

Lisp
1
2
3
4
5
6
7
8
9
(defun tabulate (f a b h)
   (iter (for x from a to b by h)
      (collecting (try (funcall f x) except 'err))))
 
==> TABULATE
 
(tabulate (lambda (x) (/ 1 (- x 5))) 1 10 1)
 
==> (-1/4 -1/3 -1/2 -1 ERR 1 1/2 1/3 1/4 1/5)
1
4527 / 3521 / 358
Регистрация: 12.03.2013
Сообщений: 6,038
27.09.2016, 20:35 3
Цитата Сообщение от 4_d4 Посмотреть сообщение
То получаем деление на ноль и ошибку.
А что вы хотели? lim надеется, что передаваемая ему "последовательность" является функцией, определённой на множестве натуральных чисел. А ваша лямбда n -> n/(5 - n) не является функцией, определённой на множестве натуральных чисел. Как говорится, junk in junk out.

На вашем месте я бы хранил два последних вычисленных значения в переменных - параметрах do.
0
43 / 15 / 2
Регистрация: 27.02.2016
Сообщений: 36
28.09.2016, 09:03  [ТС] 4
Пошёл по пути подсказанному Catstail . Нашёл в стандарте ANSI CL функцию ignore-errors, которая решает проблему.

Lisp
1
2
3
4
5
6
7
8
9
(defun lim (fn e)
  (do ((i 1 (+ i 1)))
      ((ignore-errors (or (< (abs (- (funcall fn i)
                                     (funcall fn (+ 1 i))))
                                   e)
                          (< 100000 (funcall fn (+ 1 i)))))
       (if (< 100000 (funcall fn (+ 1 i)))
           nil
           (* 1.0 (funcall fn (+ 1 i)))))))
Lisp
1
2
CL-USER> (lim #'(lambda(n)(/ n (- 5 n))) 0.00001)
-1.0070622
0
4527 / 3521 / 358
Регистрация: 12.03.2013
Сообщений: 6,038
28.09.2016, 12:31 5
Ваша функция стала ещё глупее. И глючнее. Попробуйте подсунуть ей странную fn - например, #'char= - зациклится.
0
43 / 15 / 2
Регистрация: 27.02.2016
Сообщений: 36
28.09.2016, 13:24  [ТС] 6
Цитата Сообщение от helter Посмотреть сообщение
Ваша функция стала ещё глупее. И глючнее. Попробуйте подсунуть ей странную fn - например, #'char= - зациклится.
Я понимаю, что если написать что-то вроде.

Lisp
1
(lim #'(lambda(n)(cos (* n pi))) 0.00001)
То функция зациклит так как значение fn будет меняться с -1 до +1.

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

Впрочем, если кто-нибудь предложит универсальную и эффективную версию lim, с удовольствием взгляну на код в этой или в другой теме.
0
4527 / 3521 / 358
Регистрация: 12.03.2013
Сообщений: 6,038
28.09.2016, 17:38 7
Работа с ошибками - это прекрасно. В лиспе роскошная система работы с состояниями (condition, частным случаем которого является ошибка). Но у вас нет логики в решении. Функция lim не должна глушить ошибку. Если что-то идёт не так (вместо нормальной последовательности подсунули функцию, определённую не на всех натуральных числах или вообще не на числах), честный и правильный выход - сообщить об этом, поднять тревогу. То есть не глушить ошибку, если она есть. А что с ней делать - пусть решают выше по стеку.

Для аналогии - функция деления. Если предлагают делить на ноль - она кидает ошибку. Потому что в её компетенцию не входит решать то, что в таком случае делать. Выше по стеку ошибку отловят и сделают то, что нужно в конкретном приложении: проигнорируют, или напечатают предупреждение, или предложат пересчитать с новым знаменателем (можно даже так).

То есть в вашем случае надо было бы оборачивать сверху lim в ignore-errors, а не внутрь его засовывать. Либо - фиксить функцию до того, как её передают lim-у, то есть оборачивать во что-то лямбду.

Насчёт умного алгоритма ничего не могу сказать. Если вы пишете в стиле числяков, это в любом случае эмуляция математического предела. Ваша эмуляция странна тем, что вылетает из цикла при виде первого попавшегося большого положительного числа (на отрицательные при этом не реагирует. Сравните
Lisp
1
2
(lim #'(lambda(n) (/ 1 (- n 1.999999))) 0.0001)
(lim #'(lambda(n) (/ 1 (- n 2.000001))) 0.0001)
Об ошибках хорошо написано в соответствующей главе "Практического Common Lisp". В общем и целом дело обстоит так:

1) Состояния образуют иерархию, можно создавать новые.

2) Можно перехватить ошибку, размотав стек: макрос handler-case (ignore-errors - его частный случай).

3) Можно перехватить ошибку, не разматывая стек - макрос handler-bind. С помощью рестартов можно возвратиться вниз, чтобы исправить ошибку. Когда вы попадаете в дебаггер и видите там штуки типа [ABORT] - это рестарты. Их можно выбирать автоматически и, конечно, создавать новые.
3
28.09.2016, 17:38
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
28.09.2016, 17:38
Помогаю со студенческими работами здесь

Выражение в качестве параметра функции
Есть массив данный $array. При проходе по массиву через for ($x=1; $x&lt;=$bars; $x++) {} ...

Использование функции в качестве параметра
Добрый день! У меня есть класс, каждый раз при создании которого, мы соединяем его со слотом. Для...

Передача функции в качестве параметра
Как передать функцию с параметрами в transform? Т.е., например, мне надо из каждого числа вектора...

Передача функции в качестве параметра
Все привет. Помогите в решении следующей проблемы: есть класс XXX, один из методов которого...

Передача функции в качестве параметра
Есть ф-я для отправки формы аяксом function ajaxFormRequest(form_id, url, dataT, some_func) { ...

Передача строки в качестве параметра функции
Здравствуйте , помогите ,пожалуйста , с некоторыми вопросами по VBA. Есть 2 строки , нужно...


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

Или воспользуйтесь поиском по форуму:
7
Ответ Создать тему
Опции темы

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