tgoop.com/cpplastic/361
Create:
Last Update:
Last Update:
У Prolog bool
. І я все ніяк не міг зрозуміти, а як же звідти щось інше діставати. Зрозуміло, що там зіставлення з шаблоном, як в якомусь Haskell чи Erlang, але все одно. Навіть дивився приклади — та не вкладалося в голові. Розповідаю, отже.
Є, наприклад, предикат number_string
. Працює отак:
?- number_string(42, "42").
true.
Можна перевіряти, чи число співпадає зі своїм представленням у вигляді рядка. Зручно, але шо далі? А ось що:
?- number_string(42, Str).
Str = "42".
?- number_string(Num, "42").
Num = 42.
Тобто ви просто ставите замість одного з параметрів змінну (з великої літери), а воно, якщо може, матчить його зі значенням, з яким предикат видаватиме
true
. Причому це можна робити в обидва боки! Іншими словами, у вас параметри предиката — це і «вхідні», і «вихідні» разом. How cool is that?!Ось парсинг першого рядка вхідних даних, що я давав на початку попереднього допису:
parse_button_a(Line, X, Y) :-
split_string(Line, ",:", " ", ["Button A", Xs, Ys]),
parse_num('X', Xs, X),
parse_num('Y', Ys, Y).
У
parse_button_a
я за задумом першим параметром даю текстовий рядок й очікую, що X та Y воно виведе само. Для цього мають виконуватися правила під ним. Перше правило: якщо я цей рядок сплітаю по комі та двокрапці (і прибираю зайві пробіли), то очікую, що останній параметр заматчиться зі списком з трьох штук. Перша — це сталий рядок "Button A"
, а другий та третій — це рядки зі значеннями для координат (наприклад, "X+94"
та "Y+34"
). Два наступних правила вже працюють якраз з ними й фактично дістають з рядків числа. Глянемо всередину.parse_num(Var, String, Number) :-
atom_chars(String, [Var, Sign|Rest]),
atom_chars(NumStr, [Sign|Rest]),
atom_number(NumStr, Number).
Тут три параметри — назва координати (
Var
), рядок з попереднього правила та відповідне числове значення. atom_chars
матчить рядок зліва зі списком атомів (а ля констант) справа. Тож перший з них бере рядок і деконструює його на Var
('X'
), Sign
('+'
) і решту (['9', '4']
). Друге правило фактично робить це у зворотній бік: справа ми даємо ['+', '9', '4']
, а зліва отримуємо '+94'
. Цими двома правилами ми, по-перше, переконалися, що це справді X
, який ми очікуємо, а по-друге, ми його відрізали з рядка, щоб не заважав. А третій предикат матчить атом (вважайте, що рядок) зліва ('+94'
) з числом справа (там буде 94
). І потім, якщо все це заматчилося, це число йде в параметри самого parse_num
. Ну короч ось так я запарсив увесь файл, а потім читернув та використав солвер лінійних рівнянь ))
solve_machine(Ax, Ay, Bx, By, Px, Py, A, B) :-
A in 0..100,
B in 0..100,
A * Ax + B * Bx #= Px,
A * Ay + B * By #= Py,
Tokens #= A * 3 + B,
labeling([min(Tokens)], [A,B]).
Він «отримує» перші шість параметрів у вигляді чисел і підбирає й «виводить» такі A й B, щоб ціна була найменша. Вуаля! )
Звісно, Prolog цим не обмежується. Теоретична база все одно потрібна, бо він і так доволі повільний (пів секунди на дві задачі), а на додачу дуже легко запитати щось, відповідь на що він шукатиме мільярд років. Попри це я зацінив!
І навіть при розвʼязанні задач на 17-й день іншою мовою, я у момент відчаю швиденько написав на Prolog робочу віртуальну машину на 8 команд з трьома регістрами памʼяті, щоб звірити результати.
Дуже раджу теж спробувати.