Заблокирован
|
|||||||||||||||||||||
1 | |||||||||||||||||||||
Зрить в корень проблемы28.08.2020, 14:23. Показов 712. Ответов 11
Как-то давно, когда я еще только начинал изучать Лисп, я пробовал писать свои реализации стандартных функций.
Это казалось мне наиболее интересным. И вот я решил написать функцию, которая будет находить наибольшее число в списке. Написал: функция хоть и делала то, что надо, но была плохой. На это мне тогда указал Catstail Вот она.
Catstail тогда подсказал как надо.
Исправлено, работает - вот и славно. Забыли. Но внутри что-то не давало покоя. И через пару дней я решил загуглить и посмотреть как другие решали эту задачу. И что я увидел? - Вопрос на StackOwerflow о том, как найти наибольшее число в списке. И ответ был плохой функцией, которая вычисляет себя два раза. И никто не исправил и не указал на эту ошибку. Человек так и пошел дальше с ошибочным представлением об этом алгоритме. А что, работает ведь? Тут задумался - " А почему мы делаем именно так. Что разных людей заставляет приходить к одному и тому же ошибочному решению?" Вот тогда я посмотрел впервые на проблему реально. Вместо того, чтобы пытаться поскорее бездумно решить проблему нужно посмотреть на ее причину. А причина проста - функция возвращает
Но ларчик же просто открывается, если призадуматься на секунду.
В тот момент я понял как и почему пишется так называемый быдло код и почему потом происходят разные проблемы с безопасностью и утечками памяти. Я думаю вот почему так важно изучать такие языки, как Lisp. Они наглядно дают это понять.
2
|
28.08.2020, 14:23 | |
Ответы с готовыми решениями:
11
не могу найти корень проблемы Не могу понять корень проблемы. Ноутбук DELL Inspiron 7577 Найти корень уравнения методом последовательных итераций.Второй корень вычисляет неверно Вычислить массу пластинки ограниченной линиями: y=корень(x-1) , y=0, x=2 с поверхностной плотностью пропорциональной 2*корень(x) . |
4527 / 3521 / 358
Регистрация: 12.03.2013
Сообщений: 6,038
|
|
28.08.2020, 15:08 | 2 |
Причина - булева слепота!
Кстати, схема из-за #t и #f более ей подвержена, чем CL. В принципе, это тоже велосипед - расписанная свёртка. Так-то это (reduce #'max list) .
0
|
4527 / 3521 / 358
Регистрация: 12.03.2013
Сообщений: 6,038
|
|
28.08.2020, 15:51 | 4 |
Точнее, nil, а не f, но дело в том, что в CL булево значение ассоциировано с любым объектом, а в схеме - только с #t и #f. В CL истинное значение несёт сколько угодно дополнительной информации.
Булева слепота возникает из-за того, что собственно булево значение несёт мало информации - один бит. Поэтому до ветвления часто вычислено больше информации, чем нужно для принятия решения, и её надо протаскивать в ветки. По-моему, функции bad и good идеально это иллюстрируют. А функция grt - что неплохо и вовсе обойтись без ветвления.
0
|
Заблокирован
|
|||||||||||||||||||||
28.08.2020, 16:23 [ТС] | 5 | ||||||||||||||||||||
Это да. Там вместо nil есть void, но это немного другое.
Nil, кстати, тоже может быть опасен в неумелых руках. например у нас есть вектор (Пишу на Clojure, так как там есть nil)
Может возникнуть такая ситуация
Поэтому функции для доступа к элементам коллекций принимает второй необязательный аргумент.
А что в CL функция
0
|
4527 / 3521 / 358
Регистрация: 12.03.2013
Сообщений: 6,038
|
|
28.08.2020, 17:06 | 6 |
Вообще, стандарт пишет "generalized boolean", то есть теоретически может быть что угодно. Но сомневаюсь, что какая-нибудь реализация возвращает что-либо кроме t или nil.
Это я просто лишний раз прорекламировал дизайн языка, но для данных примеров это неважно. На CL эти решения выглядели бы аналогично, но их недостатком была бы рекурсия вместо цикла или reduce. Ага, в CL известный пример - find со своими родственниками. У Грэма, что ли, было написано, что из-за этого лиспер может проронить скупую слезу. Если есть опасность найти nil, можно пользоваться другими функциями (member, position). А gethash, чтобы избежать аналогичной проблемы, вторым значением возвращает флаг "найдено?". Неа. Там может быть строка "Nothing". Будет надёжно, если использовать объект, сгенерированный на ходу: генсим или свежую конс-ячейку. Добавлено через 7 минут Не по теме: Немного пишу на котлине - туда насовали средств контроля над null-ами, и стала вырастать альтернативная условная система: не-null/null параллельно с true/false. Конечно, из-за джавы они от true и false не откажутся. Но вообще, забавно.
0
|
Заблокирован
|
|
28.08.2020, 18:58 [ТС] | 7 |
В Clojure тоже есть find.
Возвращать можно что угодно. "Nothing" - как пример был. Null - это та вещь от которой нужно избавиться раз и навсегда. Сам изобретатель этого null потом статью написал - "Null - ошибка ценой в миллион долларов" В Rust, например, отказались от null поэтому и вместо этого используют перечисления Result, которое может иметь значение или возвращает ошибку. И перечисление Option, которое может иметь значение или возвращает None. Суть в том, что эти перечисления в любом случае нужно проверить на отсутствие ошибки или отсутствие результата: получить доступ к значению, если оно есть, иначе невозможно.
0
|
4527 / 3521 / 358
Регистрация: 12.03.2013
Сообщений: 6,038
|
|
28.08.2020, 22:00 | 8 |
Я понимаю. "Nothing" точно так же не работает для всех списков, как не работает для них nil. И никакая другая строка. Я предполагаю, не зная Clojure, что универсальное решение для любых списков должно включать создание на лету уникального объекта.
Не слышал, чтобы в лиспе от nil были проблемы. И в строго типизированных языках типы Option весьма пригождаются. От этого добра больше прока, чем от двузначного булева типа. Есть какая-то философская разница между None и null? Не знаю раста. Конечно. Они же в качестве логических значений, поэтому естественно участвуют в ветвлениях. Которые необязательно if-ами делать. Вот, в котлине сделали монаду Option: ?. .
0
|
Заблокирован
|
||||||
28.08.2020, 22:43 [ТС] | 9 | |||||
Безусловно. Но вероятность что так окажется "Nothing" куда ниже, чем то, что там будет nil.
Ну возможные проблемы мы уже затронули выше, когда не понятно значение это или нет. Lisp - это бестиповый язык. Тем более, что современные диалекты стремятся все к большей функциональности. Например в том же С++ с null возможны серьезные проблемы. Безусловно. В самих словах, конечно, нет - None или Null - нет разницы. Нов подходе она очевидна. None - это перечисление типа Option, а получить доступ к перечислениям не так-то просто, как я говорил. Для этого нужно использовать match или другие конструкции языка. Например:
Если написать match без ветви None, то компилятор заругается. Скорее всего из Rust пришла. В Rust это сахар для макроса try!
0
|
4486 / 2721 / 485
Регистрация: 28.04.2012
Сообщений: 8,590
|
|
30.08.2020, 10:01 | 10 |
0
|
4527 / 3521 / 358
Регистрация: 12.03.2013
Сообщений: 6,038
|
|
30.08.2020, 12:51 | 11 |
Во дела, мне почему-то казалось, что в качестве логических должны быть именно #f и #f. Завязываю про схему писать.
0
|
4486 / 2721 / 485
Регистрация: 28.04.2012
Сообщений: 8,590
|
|
30.08.2020, 13:11 | 12 |
Отличие от CL только в том, что nil не является #f.
Добавлено через 5 минут https://ideone.com/aQ19bT
0
|
30.08.2020, 13:11 | |