Давайте посмотрим на ваш 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).
Пролог не имеет * функции *, которые определяют операции. Он имеет * предикаты *, которые определяют отношения. Это не одно и то же. – lurker
Отличная точка, и я все еще очень новичок в прологе, поэтому простите мое невежество. Я поставил предикатный тег на этот пост с самого начала, но я забыл также отразить это в фактическом тексте ... слишком догнал старые привычки! – freefall