Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
Пролог в чистом виде не решает всех проблем с интеллектуальными задачами, но он дает основу для их решения. И эта основа прочнее и надежнее, чем у других языков искусственного интеллекта.
это очень размытое понятие, но в последние годы оно в основном упоминается в контексте:Это исключительно ваше видение. Если же разбираться подробно, то интеллектуальных задач достаточно много. Исторически к интеллектуальным относили символьные задачи. А у вас предложены лишь вычислительные. И дальнейший спор предлагаю не развивать, т.к. он упрется в определение термина «интеллектуальный».
1. Машинного обучения
2. Интеллектуальных агентов (по сути то же машинное обучение, но с ответной реакцией)
Когда задача уже решена, и нужно только получать частные решения для разных значений параметров, заново запускать полноценный поиск решения — пустая трата ресурсов
Вся несостоятельность и нежизнеспособность PROLOG была доказана еще 40 лет назад проектом так называемых «Компьютеров пятого поколения»
Да и Гедель со своей теоремой о неполноте логических систем так и маячит.
Теорема Гёделя в данном случае означает, что не существует универсального алгоритма решения произвольных логических задач. То есть, программа на прологе может не завершается, но изменить алгоритм можно переформулировав задачу, модифицировав программу.
… вместе с программой должна поставляться кнопка «Вызов разработчика»1С вам в подарок на рождество )
Вот вы же не зовете разработчика, чтобы научиться суп варить, или там, с девушками знакомиться?Вообще-то зову. Разработчик сидит в устройстве, называемое «поваренная книга».
module Main where
import Control.Monad (guard)
import Data.List (nub)
import Text.Printf (printf)
{-
D O N A L D
+ G E R A L D
-----------
R O B E R T
-}
solutions :: [(Int, Int, Int)]
solutions = do
d <- [1..9]
o <- [0..9]
n <- [0..9]
a <- [0..9]
l <- [0..9]
g <- [1..9]
let (t:r:e:_) = revDigits (2 * unDigits [a, l, d])
donald = unDigits [d, o, n, a, l, d]
gerald = unDigits [g, e, r, a, l, d]
(_:_:_:b:_) = revDigits (donald + gerald)
robert = unDigits [r, o, b, e, r, t]
guard (donald + gerald == robert)
guard (different [d, o, n, a, l, g, e, r, b, t])
return (donald, gerald, robert)
where unDigits = foldl (\ a b -> a * 10 + b) 0
different xs = length (nub xs) == length xs
revDigits x = let (q, r) = quotRem x 10 in r:(revDigits q)
main = do
let (a, b, c):_ = solutions
printf " %d\n+ %d\n ------\n %d\n" a b c
$ time ./Main
526485
+ 197485
------
723970
real 0m0.592s
user 0m0.587s
sys 0m0.004s
программа на ПРОЛОГе в 10 раз понятнее, поскольку все использованные идентификаторы (процедуры) описаны в тексте программы
module Main where
import Data.List (permutations)
import Text.Printf (printf)
{-
D O N A L D
+ G E R A L D
-----------
R O B E R T
-}
solutions :: [(Int, Int, Int)]
solutions = filter good $ map assign (permutations [0 .. 9])
where assign [d, o, n, a, l, g, e, r, b, t] = ( unDigits [d, o, n, a, l, d]
, unDigits [g, e, r, a, l, d]
, unDigits [r, o, b, e, r, t]
)
unDigits = foldl (\ a b -> a * 10 + b) 0
good (donald, gerald, robert) = donald + gerald == robert
main = do
let (a, b, c):_ = solutions
printf " %d\n+ %d\n ------\n %d\n" a b c
в Прологе не надо думать о стеках и проблемах динамической памятиЗато надо думать, как бы логический вывод не улетел в бесконечную рекурсию, а это куда сложнее, чем придерживаться какого-нибудь простого правила типа «выделил память — не забудь освободить»
качество программы
большинство переменных задаются в виде паттерновПриведите пример такого описания. Я хочу понять, как оно защищает от опечаток.
female(john, mary), подразумевая father(john, mary). [A,B] вместо [A,B,C]. IDE/язык ничего не подскажут.Пора уже понять, что процедурный подход в программировании — временное явление.
Попробуйте полюбить рекурсию.
Все символьные объекты неизбежно рекурсивны. [...] Все модные языки — это сдача позиций перед неизбежностью декларативности символьных структур.
Насчет смены парадигм — в последние десятилетия прогресс в Software Engineering резко замедлился из-за экстенсивного роста спроса на программы — крупным фирмам и так хороши живется.
Насчет рекурсии — как учил Дейкстра «структура программы должна соответствовать структуре данных». Если работаем с массивами и файлами — нужны циклы, если со списками (а это выражения на каком-то языке) — программа должны быть рекурсивной.
О символьных структурах надо говорить, когда на вход программы поступает не числовые записи, а выражения на некотором языке.
поскольку решение проблемы автоматизации программирования неизбежно
Программистам останется проектирование приложений
Не согласен
Трендовые (или модные) языки вынуждены работать с HTML, XML.
QuickSort есть в Интернете
2-SAT — как и всякую поисковую задачу удобно запрограммировать на ПРОЛОГе
Под проектированием я понимаю работу системного аналитика, который полностью, точно, специфицирует проект, т.е. программистам придется переквалифицироваться в системные аналитики.
Вы задаете очень интересные вопросы, был бы рад их обсуждать и дальше, но тема у нас немного другая.
какие практические задачи по работе со списками приходится решать в повседневной работе программиста
какие практические задачи по работе со списками приходится решать в повседневной работе программиста
это актуально для Вас и широких масс программистов
Сдача позиций в том, что в императивные языки вставляют парадигмы функционального и логического программирования.
2-SAT — тема для отдельных публикаций. Если Вы убедите меня, что это актуально для Вас и широких масс программистов
bool check_compatibility(int x, int y);
bool find_x_compatible_to_y(int& x, int y);
bool find_y_compatible_to_x(int x, int& y);
bool find_any_compatible(int& x, int& y);
compatible(X, Y) :- ..... .
slow(X) :- ... . // медленная проверка/перебор
fast(X) :- ... . // быстрая проверка/перебор
check1(X) :- fast(X), slow(X).
check2(X) :- slow(X), fast(X). // то же самое, что выше, но гораздо медленнее
// предикат удовлетворяет цепочкам, составленным из a и b
abstring( [] ).
abstring( [a|S] ) :- abstring(S).
abstring( [b|S] ) :- abstring(S).
// проверка вхождения
belongs( C, [C] ).
belongs( C, [_|Cs] ) :- belongs(C, Cs).
// ну что, взорвёмся?
abstring_with_item(C,S) :- abstring(S), belongs(C,S).
?- abstring_with_item(C,[a,a,a,a,a,b]) // пять раз найдёт, что C=a - ооочень эффективно
?- abstring_with_item(C,S) // будет выдавать решения исключительно вида C=a, S=[a], [a,a], [a,a,a]...
?- abstring_with_item(b,S) // зависнет
/*
ab(a).
ab(b).
abstring([]).
abstring([C|S]) :- ab(C), abstring(S).
Там, где на других языках пришлось бы делать 2^N функций
Как вы себе это представляете?
Не подумайте что я имел ввиду писать нейронки на прологе. Я вот после прочтения данной статьи полез искать как из c++ делать запросы скомпилированной базе пролога...
PROLOG для программистов