LINUX.ORG.RU
ФорумTalks

Зачем нужна обработка списков в искусственном интеллекте?

 ,


2

6

По легенде, Lisp придуман для решения задач искусственного интеллекта. Зачем для этого надо было придумывать такой довольно необычный язык - язык обработки списков? Чем например Fortran не подошёл бы?

Ответ на: комментарий от emulek

ничего не мешает. Просто это очень дорого и никак не упрощаемо.

Упрощаемо. Выделяем несколько страниц памяти, помечаем их исполняемыми и с разрешённой записью, пишем туда машинные инструкции, вызываем и модифицируем по необходимости

Harald ★★★★★
()
Ответ на: комментарий от Harald

а как ты эту визуализацию построил?

Последние 1000 сообщений пользователя можно просмотреть через его профиль, собрал оттуда. Для последних пришлось поправить даты, перевести в абсолютное значение (было «сегодня», «вчера»). Потом скормил скрипту на python+cairo, в котором перебираются сообщения подряд и рисуются линии. Каждая полоса — сутки.

Это сейчас называют модным словом «data science».

i-rinat ★★★★★
()
Ответ на: комментарий от theNamelessOne

Упрощённый алгоритм вычисления function form таков:

Корень непонимания в слове «вычислять». В лиспе функцию можно не вычислять, поскольку раскрывается она в реалтайм. А в реалтайме она может быть всегда «разной», видоизменяться в зависимости от задачи. А в Си функция всегда определена заранее, не изменяется.

iVS ★★★★★
()
Ответ на: комментарий от emulek

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

grouzen ★★
()
Ответ на: комментарий от gh0stwizard

код на си, который был в начале, аля классическая рекурсия свалится через н-десять циклов, ИБО стек процессора будет забит, в простонародье stack overflow. В отличие от такого описания, код на лиспе делает туже рекурсию, но не на стеке! Ибо никто бы не стал изобретать такой язык :)

Что на си, что на лиспе для демонстрации рекурсии первым делом перепишут этот быдлокод так, чтобы последним вызовом стал не *, а собственно функция. В итоге ничего вылетать не будет. Даже gcc умеет TCO, не говоря о лиспах.

Вопрос о нужности рекурсивного определения факториала оставим за скобками.

x3al ★★★★★
()
Ответ на: комментарий от x3al

Что на си, что на лиспе для демонстрации рекурсии первым делом перепишут этот быдлокод так, чтобы последним вызовом стал не *, а собственно функция. В итоге ничего вылетать не будет. Даже gcc умеет TCO, не говоря о лиспах.

Скорее, сразу перепишут в цикл, т.к. ни стандарт C, ни стандарт CL не требуют от реализаций поддерживать TCO. Вот со Scheme другое дело.

theNamelessOne ★★★★★
()

Для разработки полноценного ИИ (мы же говорим о полноценном, с сознанием и личностью, да?) не подходит ни один современный язык программирования, и ни одна из ныне существующих железок.
Лисп просто чуточку менее не подходит, чем остальные. А вот web-приложение на лиспе мне писать понравилось, необычный опыт, слегка психоделический. Еще написал client-side блеклист для jabber.el, который вродь работает даже.

Komintern ★★★★★
()
Последнее исправление: Komintern (всего исправлений: 1)
Ответ на: комментарий от Harald

Упрощаемо. Выделяем несколько страниц памяти, помечаем их исполняемыми и с разрешённой записью, пишем туда машинные инструкции, вызываем и модифицируем по необходимости

попробуй. У меня не получилось.

emulek
()
Ответ на: комментарий от iVS

Корень непонимания в слове «вычислять». В лиспе функцию можно не вычислять, поскольку раскрывается она в реалтайм. А в реалтайме она может быть всегда «разной», видоизменяться в зависимости от задачи. А в Си функция всегда определена заранее, не изменяется.

++

emulek
()
Ответ на: комментарий от grouzen

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

иди SICP почитай. ЛОР это не место для ликбеза. Я тебя всё равно не смогу ничему научить.

emulek
()
Ответ на: комментарий от x3al

Что на си, что на лиспе для демонстрации рекурсии первым делом перепишут этот быдлокод так, чтобы последним вызовом стал не *, а собственно функция. В итоге ничего вылетать не будет. Даже gcc умеет TCO, не говоря о лиспах.

это всё верно конечно, вот только это уже _другой_ алгоритм, НЕ рекурсивный, а итеративный.

Вопрос о нужности рекурсивного определения факториала оставим за скобками.

ну попробуй обойти бинарное дерево итеративно, что-бы рекурсия была только хвостовая. С факториалом у тебя получилось лишь потому, что входная информация представляет собой итеративную функцию. Ты её можешь считать _последовательно_. А вот с деревом — увы. Также и сортировки на месте, и ещё Over9000 других задач.

Обычно, даже дело не в том, что это невозможно, нет, возможно. Вот только вариантов получается чуть более, чем до хрена (у меня тут 27! получилось), если решать перебором. Если-же задачу решать рекурсивно, сохраняя путь и возвращаясь, то решить часто можно за вполне обозримое время, потратив не так уж и много памяти. Вот только в цикл это уже никак не сворачивается.

emulek
()
Ответ на: комментарий от theNamelessOne

Скорее, сразу перепишут в цикл, т.к. ни стандарт C, ни стандарт CL не требуют от реализаций поддерживать TCO.

хвостовая рекурсия это и есть цикл. В сишечке она просто не нужна, ибо эквивалентна goto (это слово в сишечке ещё никто не отменил).

Конечно, IRL вместо goto пишут while, ибо

1. можно выйти из середины цикла (break)

2. можно продолжить цикл из середины (continue)

3. можно поставить условие выхода в конец или в начало цикла.

Короче — вопрос исключительно удобства и стиля.

И да, несмотря на это, gcc всё равно умеет TCO.

emulek
()
Ответ на: комментарий от Komintern

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

ты так уверенно говоришь, как будто бы у тебя есть пруфы.

А может ты просто не осилил?

emulek
()
Ответ на: комментарий от olibjerd

Сама идея списка позволяет удобно заниматься метапрограммированием.

дык потому, что алгоритм == список действий. Только одного списка недостаточно, нужно ещё что-то. Ну например можно пронумеровать все действия, и сделать условное goto на любое действие. Это универсальный способ, но он слишком универсален — такую программа несложно написать (если она короткая), несложно выполнить, но очень сложно её читать, поддерживать, и упрощать. Намного лучше и удобнее, когда у нас есть набор из нескольких стандартных строительных блоков, например всего _один_ вид такого блока — функция. Этого достаточно. Очевидно, автоматическая обработка одинаковых блоков максимально проста, и если она возможна, то скорее всего именно она.

emulek
()
Ответ на: комментарий от gh0stwizard

Объясню на пальцах (хоть лисп не знаю): код на си, который был в начале, аля классическая рекурсия свалится через н-десять циклов, ИБО стек процессора будет забит, в простонародье stack overflow. В отличие от такого описания, код на лиспе делает туже рекурсию, но не на стеке! Ибо никто бы не стал изобретать такой язык :) Аналог на Си делается через создание новой ссылки на функцию и все вычисления производятся в куче

Так ведь и описанный лисповый код болеет той же болезнью — хвостовой рекурсии нет --> тоже свалится с нехваткой памяти при определенном n.

habamax ★★★
()
Ответ на: комментарий от habamax

Я не спец по лиспу. Думал там эти проблемы решены. Тогда пример теряеет всякий смысл.

gh0stwizard ★★★★★
()
Ответ на: комментарий от habamax

Так ведь и описанный лисповый код болеет той же болезнью — хвостовой рекурсии нет --> тоже свалится с нехваткой памяти при определенном n.

в данном примере нет ХР. Т.ч. эта ваша схема тоже должна рухнуть (IRL не рухнет ибо либо будет переполнение, или зависнет. Зависнет потому, что факториал растёт БЫСТРЕЕ экспоненты, потому каждое следующее произведение будет считаться ДОЛЬШЕ предыдущего. Ибо время умножения растёт как логарифм числа. Т.е. скорость будет очень быстро падать, и мы просто не дождёмся некоторых результатов, начиная с очень небольшого n, причём на _любом_ компьютере. Также и потребляемая память будет БЫСТРО расти, ибо на число нужно тоже логарифм байтов. Потому память кончится не из-за стека, а из-за слишком длинных чисел).

emulek
()
Ответ на: комментарий от harm

Задача по символьному дифференциированию численно не решается. Инфа 100%.

учи матчасть. В ОБЩЕМ случае не решается. В частном случае очень даже решается. В частности, если функция == многочлен по степеням. И очевидно, если функция == что угодно, приводимое к многочлену по степеням. И, ЕМНИП, частное двух многочленов — тоже дифференцируемо численно(конечно если договорится не делить на ноль), т.о. дифференцируемо любое выражение, составленное из сумм/произведений и даже частных любых многочленов по степеням. Численно.

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

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

emulek
()
Ответ на: комментарий от emulek

Ты, похоже, вообще не читаешь что тебе пишут, либо, как вариант, не понимаешь чем отличаются символьное и численное дифференциирование.

harm
()
Ответ на: комментарий от harm

Ты, похоже, вообще не читаешь что тебе пишут, либо, как вариант, не понимаешь чем отличаются символьное и численное дифференциирование.

Ок. Давай на примере: возьмём многочлен x^3 + 3*x^2 + 5*x. Проведи символьное дифференцирование(ручками), и посмотри на результат. И ты всё поймёшь.

emulek
()
Ответ на: комментарий от emulek

Т.е. скорость будет очень быстро падать, и мы просто не дождёмся некоторых результатов, начиная с очень небольшого n, причём на _любом_ компьютере.

Если только на _любом_ компьютере не значит на любом сферическом компьютере в вакууме. А на любом *существующем* ныне компьютере при использовании этой реализации алгоритма расчета факториала достаточно большого n мы выберем всю доступную память за конечный временной промежуток. И не получим результата именно по этой причине.

Потому память кончится не из-за стека, а из-за слишком длинных чисел).

О господи, о чем спор то? " --> тоже свалится с нехваткой памяти при определенном n" здесь просто говорится о нехватке памяти.

habamax ★★★
()
Ответ на: комментарий от emulek

Ок. Давай на примере: возьмём многочлен x^3 + 3*x^2 + 5*x. Проведи символьное дифференцирование(ручками)

3x^2 + 6x + 5

Теперь твоя очередь: возьмём функцию sin(kx). Продифференциируй по х на фортране. Можно численно. Можно с использованием разложения в ряды тейлора. Только, чтоб на выходе получилось cos(kx).

harm
()
Ответ на: комментарий от habamax

мы выберем всю доступную память за конечный временной промежуток.

с существующей реализацией больших чисел — да. Потому-что она оптимизированы на скорость, а не на объём. Но можно сделать свой велосипед, который будет работать настолько медленно, что просто не успеет пожрать всю память за обозримое время :)

О господи, о чем спор то? " --> тоже свалится с нехваткой памяти при определенном n" здесь просто говорится о нехватке памяти.

разная «нехватка». Нехватка памяти под сами числа к нашему спору не относится. Можно ведь считать не факториал, а просто сумму чисел по ЭТОМУ алгоритму. С т.з. алгоритмов разницы никакой, только не будет переполнения, и числа будут маленькие. И проверить проще, ибо сумма арифметической прогрессии заранее известна.

Алгоритм можно изменить также так, что-бы он запоминал не каждое число, а каждый раз вдвое больше чисел. Тогда стек будет расти логарифмически, а не линейно. И его по любому хватит для любых применений. Т.о. ограничение на машинный стек, на самом деле не такое страшное, как кажется. Да, мы не знаем его размер, но точно знаем, что логарифм чего угодно туда влезет.

emulek
()
Ответ на: комментарий от olibjerd

и список в Лиспе это разные понятия.

я это прекрасно понимаю. Фишка в том, что список в лиспе тоже можно использовать как алгоритм. Это не одно и то же, однако можно использовать одно в качестве отображения другого.

emulek
()
Ответ на: комментарий от harm

Ок. Давай на примере: возьмём многочлен x^3 + 3*x^2 + 5*x. Проведи символьное дифференцирование(ручками)

3x^2 + 6x + 5

молодец. Разве тебе непонятно, что _в_ _этом_ случае численное и символьное эквивалентно?

Теперь твоя очередь: возьмём функцию sin(kx).продифференциируй по х на фортране. Можно численно. Можно с использованием разложения в ряды тейлора. Только, чтоб на выходе получилось cos(kx).

Дык это и не многочлен. А ты это в многочлен преобразуй, и получишь то, что надо.

тут фишка в том, что sin(kx) вообще говоря раскладывается по степеням sin(x). Т.е. если k — целое число, то sin(kx) является многочленом по степеням sin(x) и cos(x) (последний на самом деле элементарно выражается через sin, но тебе этого как раз и не нужно). Да, если k это не 2 и не три, а скажем 10, то многочлен займёт пол страницы, но тебе же его не ручками считать? Не вижу проблемы. Вот с рациональным k — я не помню. Просто уже много лет прошло. Как-то и эта проблема решается, без всяких LISP'ов, только надо голову подключить. Я видел такую программу, причём видел давно, и ЧСХ она похоже как раз на фортране была написана.

emulek
()
Ответ на: комментарий от emulek

Разве тебе непонятно, что _в_ _этом_ случае численное и символьное эквивалентно?

В данном случае, мне понятно, что ты не знаешь что такое численное дифференциирование. И лисп ты тоже не знаешь.

А ты это в многочлен преобразуй

Нет. Я хочу, чтобы ты это сделал.

Не вижу проблемы.

А я не вижу кода. Что, к слову, и является наилучшим ответом на ворос Т.С.

harm
()
Ответ на: комментарий от olibjerd

Макросы для императивщины?

фи... Зачем так грубо? Лучше посмотри на нашу программу вычисления факториала на сишечке: если её записать в виде списка, то увидим, что на самом деле это никакая не рекурсия, а самый просто безусловный цикл. Причём это наше «увидим» вполне реально выразить формально. В данном случае, контекст функции внутри рекурсивного вызова НЕ отличается от контекста снаружи. Точнее отличие очень простое, надо на входе сделать n--, а на выходе n++. Вот и вся разница. Это несложно найти не своим интеллектом, а компьютерным. Ну а раз так, то нам не нужна рекурсия вовсе. Достаточно цикла и массива, в последний будем складывать n--, а потом их помножим

int factorial(n0)
{
  int a[n];
  int n = n0;
  int y = 1;
  while(n)
    a[n] = n--;
  while(n <= n0)
    y *= a[n++];
  return y;
таким образом мы поменяли рекурсию на массив и цикл (это не ХР, потому понадобился массив, а не только цикл).

Дальнейшие оптимизации тривиальны (можно ещё избавится от массива, а вычислить данные по ходу движения. Тут и считать ничего не нужно. Потом можно слить два цикла в один, для этого необходимо, что-бы наш алгоритм знал, что a*b*c*d === d*c*b*a, тогда он сможет менять местами порядок в цикле на обратный)

emulek
()
Ответ на: комментарий от emulek

Лучше посмотри на нашу программу вычисления факториала на сишечке:

Главное — вовремя соскочить с темы.

Удачи в этом треде.

olibjerd ★★★★★
()
Последнее исправление: olibjerd (всего исправлений: 1)
Ответ на: комментарий от harm

А я не вижу кода.

этот код несложно нагуглить при желании. Для его написания достаточно вот этих соотношений:

sin(α + β) = sinα cosβ + cosα sinβ
cos(α + β) = cosα cosβ - sinα sinβ
я надеюсь ты в курсе, как разложить любое число на сумму степеней двойки? В компьютере этого и делать не нужно, числа там и так разложены. Также я думаю тебе не составит труда выразить sin(2α), sin(4α), sin(8α)...

Разве не очевидно, как теперь выразить sin(kα) в виде многочлена? Осталось посчитать производную sin(α) и cos(α), сам знаешь, сколько получится. Вот и всё.

Такой алгоритм выразит производную sin(kα) для любого целого k в виде многочлена от sin и cos.

Я только не очень понимаю, зачем тебе этот код?

emulek
()
Ответ на: комментарий от olibjerd

Главное — вовремя соскочить с темы.

ты название темы и первый пост вообще читал? Соскочить ты попытался.

emulek
()
Ответ на: комментарий от grouzen

я удаляюсь с этого упоротого треда.

молодец. Ссылку на SICP дать, или сам?

emulek
()
Ответ на: комментарий от emulek

Я только не очень понимаю, зачем тебе этот код?

Слова очень дёшево стоят. Словами можно сказать неправду. Слова ничего не стоят, против других слов.

Код же является наилучшим доказательством. Прямо как эксперимент в физике.

harm
()
Ответ на: комментарий от harm

Слова очень дёшево стоят. Словами можно сказать неправду. Слова ничего не стоят, против других слов. Код же является наилучшим доказательством. Прямо как эксперимент в физике.

разве из наброска алгоритма тебе не очевиден код? Я вроде всё разжевал досконально.

Давай повторю в виден псевдокода:

1. создаём таблицу sin(2α), sin(4α), sin(8α)...

2. раскладываем k по степеням двойки

3. раскладываем sin(ka) на sin и cos.

4. численно дифференцируем.

5. упрощаем результат.

Какой пункт тебе непонятен?

emulek
()
Ответ на: комментарий от emulek

разве из наброска алгоритма тебе не очевиден код?

Мне очевидно, что ты не хочешь предоставить работающий код. Я хочу посмотреть как ты утонешь в безднах говнокода, а ты отделываешься общими словаесами.

в виден псевдокода:

В виде псевдокода я тебе что хочешь напишу: хоть решалку дифуров, хоть ИскИн для управления государством. Одна беда --- не компилируется. ;-(

harm
()
Ответ на: комментарий от mentalmenza

так а в чём разница с

В том, что Lisp — 1958
Си — 1972

Даже в наше время 14 лет разницы — это много. А тогда — это несколько разных эпох.

KRoN73 ★★★★★
()
Ответ на: комментарий от Harald

что мешает сишной программе сгенерировать текст программы на С, вызвать компилятор, а скомпилированный код динамически слинковать и вызвать? :)

картинка-с-троллейбусом-из-буханки-хлеба.pcx

KRoN73 ★★★★★
()
Ответ на: комментарий от harm

Мне очевидно, что ты не хочешь предоставить работающий код. Я хочу посмотреть как ты утонешь в безднах говнокода, а ты отделываешься общими словаесами.

дык эта задача не слишком сложная, но довольно громоздкая. Когда-то я такую уже решил. Зачем мне ещё раз повторяться? Да и всякие фортраны/сишечки всё равно хоть и подходят, но не очень хорошо к таким задачам.

В виде псевдокода я тебе что хочешь напишу: хоть решалку дифуров, хоть ИскИн для управления государством. Одна беда --- не компилируется. ;-(

какой именно пункт тебе непонятен и у тебя не компилируется?

emulek
()
Ответ на: комментарий от KRoN73

Даже в наше время 14 лет разницы — это много. А тогда — это несколько разных эпох.

тогда особой нужды в сишечке просто не было. Код писали под конкретную архитектуру. А под конкретную архитектуру у сишечки только одни минусы, по сравнению с ассемблером. Что-бы появилась сишечка, понадобилось выполнение двух условий:

1. появилась нужда переносить множества кода на другую архитектуру. Кода стало слишком много. Очевидно, для этого его нужно было писать _изначально_ переносимо, т.е. например брать НЕ «целые числа в 16 бит», а «типичные целые числа», т.е. именно такие, как есть в сишечке. Ну и всё остальное в том же духе.

2. программы стали довольно большие, и собрать ВСЁ СРАЗУ стало не очень реально. Да ещё и учитывая, что авторов стало больше одного. Потребовалась какая-то система автоматической сборки, ну и соответственно, блоки тоже должны были следовать определённым соглашениям, дабы их можно было линковать не руками, а make'ом (т.е. сама линковка линкером конечно, но что и как собирать — решает make). Что-бы это всё взлетело, требовалась поддержка и со стороны ЯП. Т.е. каждый модуль должен был состоять из двух частей, заголовочного, и реализации. В сишечке такая структура by design.

Пока эти условия были не выполнены, сишечка была тупо не нужна. Ну а с LISP'ом — совсем другая история.

emulek
()
Ответ на: комментарий от harm

Увы, из примера этой дискусии следует обратное.

увы, мне лень решать всю эту задачу. Если ты считаешь, что мой псевдакод не годен, выбирай самый сложный (для меня) пункт, я покажу, как его реализовать.

Лично мне непонятно, в чём твои затруднения?

emulek
()
Ответ на: комментарий от emulek

увы, мне лень решать всю эту задачу.

Если примитивнейшие, простейшие вещи превращаются в сложные, нерешаемые задачи, то мы вынуждены констатировать: этот инструмент не подходит.

Если ты считаешь, что мой псевдакод не годен,

Не компилируется => не годен.

Лично мне непонятно, в чём твои затруднения?

Это у тебя затруднения, которые почему-то мешают тебе решить простейшую задачу.

harm
()
Ответ на: комментарий от emulek

тогда особой нужды в сишечке просто не было.

Нужда была. Потребность в языках высокого уровня была с самого начала. И появление того же Lisp'а — тому пример.

А под конкретную архитектуру у сишечки только одни минусы, по сравнению с ассемблером.

Ой, как всё запущено-то :D

появилась нужда переносить множества кода на другую архитектуру

Эта нужда стала актуальной только в 1980-е гг.

Средства программирования, не привязанные к архитектуре были почти с самого начала. Тот же Фортран (1957) был переносимым даже лучше Си.

программы стали довольно большие, и собрать ВСЁ СРАЗУ стало не очень реально

Фортран был модульный с самого начала.

Да ещё и учитывая, что авторов стало больше одного.

Вот сразу видно человека, который не сталкивался с Фортраном.

KRoN73 ★★★★★
()
Ответ на: комментарий от KRoN73

Нужда была. Потребность в языках высокого уровня была с самого начала. И появление того же Lisp'а — тому пример.

ну до сишечки тоже ЯП были. Только они были менее удобными.

А под конкретную архитектуру у сишечки только одни минусы, по сравнению с ассемблером.

Ой, как всё запущено-то :D

где я не прав?

Эта нужда стала актуальной только в 1980-е гг.

угу. И именно тогда сишечку и стали пихать везде где надо, ИЧСХ, где не надо.

Фортран был модульный с самого начала.

да, но ИМХО та модульность была с самого начала костыльной.

Вот сразу видно человека, который не сталкивался с Фортраном.

ну и не спорю. На фортране я написал палу хэлловорлдов, причём очень давно. ИМХО фортран слишком жёсткий, да и вообще позволяет работать лишь с числами. Сишечка в этом плане более свободный ЯП, ближе к этому вашему LIP'у.

emulek
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.