2015-04-10 3 views
3

У меня есть (или много) проблемы со списками списков в прологе.Пролог создать список списков

Итак, у меня есть список чисел, например [5,6,1,3] в качестве входных данных. Выход должен быть [[5,25], [6,36], [1,1], [3,9]].

У меня уже есть предикат, что «возвращение-х годах 2 списка запись (имейте в виду, что я буду иметь, чтобы изменить функцию get_squared_pair, чтобы получить некоторую другую соответствующую величину):

get_squared_pair(Number, Result) :- 
get_squared_value(Number, SquareValue), 
Result = [Number, SquareValue]. 

get_squared_value(Number, Result) :- 
Result is Number * Number. 

Пока здесь нет, вполне логично , Теперь мне нужен предикат, который рекурсивно повторяет список, добавляет квадрат в новый список, а затем возвращает списки списков. То, что я прямо сейчас:

return_list([], 0). 
return_list([Head | Tail], Result) :- 
get_squared_pair(Head, Add), 
append(Add,Result), 
return_list(Tail, Result). 

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

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

Любая помощь была бы высоко оценена!

+2

Пролог не имеет * функции *, которые определяют операции. Он имеет * предикаты *, которые определяют отношения. Это не одно и то же. – lurker

+1

Отличная точка, и я все еще очень новичок в прологе, поэтому простите мое невежество. Я поставил предикатный тег на этот пост с самого начала, но я забыл также отразить это в фактическом тексте ... слишком догнал старые привычки! – freefall

ответ

3

Давайте посмотрим на ваш get_squared_pair/2. Хотя он работает, его можно немного подобрать, что также поможет понять, как работает Prolog. Основным механизмом Prolog является унификация, что не совпадает с присвоением, которое встречается на других языках. В объединение, Prolog исследует два термина и пытается унифицировать их путем создания переменных в одном или обоих терминах, чтобы они совпадали. В Прологе есть некоторые предикаты, такие как is/2, которые используются для оценки выражений в одном аргументе, а затем объединяют первый аргумент с этим результатом.

Ваш первый предикат, то, что вы написали, как:

get_squared_pair(Number, Result) :- 
    get_squared_value(Number, SquareValue), 
    Result = [Number, SquareValue]. 

get_squared_value(Number, Result) :- 
    Result is Number * Number. 

Может быть упрощена двумя способами. Во-первых, вы можете объединить get_squared_value/2, так как это всего лишь одна строка и не нуждается в собственном предикате. И мы переименуем предикат, так что это не обязательно.

square_pair(Number, Square) :- 
    S is Number * Number,  % Square the number 
    Square = [Number, S].  % Unify Square with the pair 

Пролог может объединить термины в голову оговорки, так что вы можете избежать избыточного объединения. Так что это все, что вам нужно:

square_pair(Number, [Number, Square]) :- 
    Square is Number * Number. 

к основному предиката return_list/2. Сначала мы переименуем этот предикат в square_pairs. При выполнении рекурсии со списками наиболее распространенным шаблоном является продолжение сокращения списка до его пустого, а затем базовый регистр обрабатывает пустой список. Ваша реализация делает это, но базовый случай немного запутался, так как второй аргумент является целым числом, а не список:

square_pairs([], 0). 

Это действительно должно быть:

square_pairs([], []). 

Ваш главный пункт сказуемое ISN» t правильное использование append/2. Существуют две формы: append в SWI Prolog: append/2 и append/3. Вы можете посмотреть, что они делают в онлайн-документации SWI Prolog. Могу сказать, что в Prolog вы не можете изменить значение переменной в предложении предиката после того, как оно было создано, за исключением обратного отслеживания.Например, обратите внимание на следующую последовательность, которая может быть в предложении предикат:

X = a, % Unify X with the atom 'a' 
X = b, % Unify X with the atom 'b' 

В этом случае второе выражение будет всегда не потому, что X уже унифицирована и не могут быть объединены снова. Однако, если у меня есть это:

foo(X), % Call foo, which unifies X with a value that makes 'foo' succeed 
bar(X, Y), % Call bar, which might fail based upon the value of 'X' 

В приведенном выше случае, если bar(X, Y) не удается, то Пролог отступиться к foo(X) вызова и искать другое значение X, что делает foo(X) успеха. Если он найдет один, то он снова вызовет bar(X, Y) с новым значением X и так далее.

Таким образом, append(Add, Result) не добавляет Add к Result, давая новое значение для Result. Фактически, append с двумя аргументами говорит, что второй аргумент списка представляет собой конкатенацию всех элементов первого списка, предполагая, что первым аргументом является список списков, поэтому определение append/2 не соответствует.

Когда вы думаете о своей рекурсии, поймите, что списки аргументов находятся в взаимно однозначном соответствии друг с другом. Глава списка результатов - это «квадратная пара» для главы списка в первом аргументе. Затем, рекурсивно, хвост второго аргумента представляет собой список квадратных пар для хвоста первого аргумента. Вам просто нужно выразить это в Прологе. Мы также можем использовать описанную выше методику для унификации в головке .

square_pairs([Head | Tail], [SqPair | SqTail]) :- 
    square_pair(Head, SqPair), 
    square_pairs(Tail, SqTail). 
square_pairs([], []). 

Теперь есть другое упрощение мы можем сделать, что полностью устранить square_pair/2 вспомогательный предикат:

square_pairs([Head | Tail], [[Head, SqHead] | SqTail]) :- 
    SqHead is Head * Head, 
    square_pairs(Tail, SqTail). 
square_pairs([], []). 

Там очень удобный предикат в Прологе называется maplist, которые могут быть использованы для определения отношений, которая проходит параллельно между двумя списками, то есть сценарий, который мы здесь имеем. Мы можем вернуть square_pair/2 предикат и использовать maplist:

square_pairs(Numbers, SquarePairs) :- 
    maplist(square_pair, Numbers, SquarePairs). 
+0

Спасибо за очень подробный и описательный ответ! Многому научился. Определенно выкристаллизовывали некоторые из концепций пролога в моем сознании. Я должен буду прочитать его еще несколько раз, чтобы полностью понять это;) Еще раз спасибо! – freefall

2

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

Все, что вам нужно сделать, это сообщить об этом в Пролог. Первый, второй:

turn_into_two(Num, [A,B]):- 

Что такое A?

A is Num, 

Что такое B? Мы просто расскажем об этом также Прологу:

   B is ... * ... . 

Сейчас в нашем списке. Список [A|B] в Prolog состоит из элемента головки A и его хвоста B - если только это пустой список [], конечно. Не имеет значения что элементы списка; список - это список.

Мы должны учитывать все случаи, или же мы не говорим о списках, но что-то еще:

turn_list([], Res):- 

так, что это наш результат в случае, если список был пуст? Он также должен быть пустым, верно?

Res = ... . 

в другом случае,

turn_list([A|B], Res):- 

наш результат не будет пустым, так что это будет его голову и хвост, правильно?

Res = [C|D], 

рядом мы говорим, что мы знаем о руководителях: голова списка входов превращается в этот список два элемента мы описанный выше, верно?

turn_into_two(A,C), 

, а затем мы говорим наш фрагмент о хвостах. Но что мы знаем о хвостах? Мы знаем, что один является результатом преобразования другого, так же, как весь список:

turn_list(... , ...) . 

И это все. Кстати, то, что мы описали, следует парадигме картирования. Мы могли бы использовать любой другой предикат вместо turn_into_two/2, и его получил бы вызов для каждого из элементов списка ввода вместе с соответствующим элементом из результирующего списка.

Смежные вопросы