Печатать последовательность чисел в прологе - PullRequest
0 голосов
/ 29 апреля 2018

Я хотел создать последовательность чисел в Прологе. Так, если функция print(4,3,10), она напечатает 4 7 10 13 16 19 22 25 28 31 . Второй параметр определяет следующее число, а последний параметр определяет, где последовательность должна остановиться.

У меня есть код, но, похоже, он не работает.

print(A,B,C) :- C>=0. print(A,B,C) :- D is A+B, E is C-1, print(D,B,E), write(D).

Результат показывает только true.

Есть ли решения для этой проблемы? Спасибо.

Ответы [ 3 ]

0 голосов
/ 29 апреля 2018

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

print(_A,_B,0).
print(A,B,C) :-
   D is A+B,
   E is C-1,
   print(D,B,E),
   write(D).

... ваш предикат уже дает ответы:

?- seq_step_len(4,3,10).
3431282522191613107
true ;
ERROR: Out of local stack

Обратите внимание, что перед первыми двумя аргументами нерекурсивного правила есть подчеркивание. Это позволяет избежать одиночных предупреждений при загрузке исходного файла. Однако последовательность начинается не с 4, а с 34, она не заканчивается с 31, а с 7, и между цифрами нет пробела. И тогда есть эта ошибка ERROR: Out of local stack. Последнее вы можете легко избежать, добавив цель C>0 в ваше рекурсивное правило. Неправильное начальное / конечное число можно избежать, написав A вместо D. Для обращения к обратной последовательности вы можете написать A до рекурсии. И чтобы добавить пробелы между числами, я бы предложил использовать format / 2 вместо write/1. Тогда print2/3 может выглядеть примерно так:

print2(_A,_B,0).
print2(A,B,C) :-
   C>0,                    % <- new goal
   format('~d ', [A]),     % <- format/2 instead of write/1
   D is A+B,
   E is C-1,
   print2(D,B,E).

Это дает желаемые результаты:

?- print2(4,3,10).
4 7 10 13 16 19 22 25 28 31 
true ;
false.

А пока вы занимаетесь этим, почему нет последовательности в списке? Тогда вы могли бы использовать его, например, как цель в другом предикате. И было бы неплохо иметь более описательное имя, которое делает более очевидным, какой аргумент к чему. Итак, давайте добавим аргумент для последовательности, тогда предикат может выглядеть примерно так:

seq_start_end_len([],_A,_B,0).
seq_start_end_len([A|As],A,B,C) :-
   C>0,
   D is A+B,
   E is C-1,
   seq_start_end_len(As,D,B,E).

Если вы используете SWI-Prolog, вам может потребоваться набрать w , чтобы просмотреть весь список:

?- seq_start_end_len(Seq,4,3,10).
Seq = [4, 7, 10, 13, 16, 19, 22, 25, 28|...] [write]
Seq = [4, 7, 10, 13, 16, 19, 22, 25, 28, 31] ;
false.

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

?- seq_start_end_len(Seq,X,3,10).
ERROR: is/2: Arguments are not sufficiently instantiated
?- seq_start_end_len(Seq,4,X,10).
ERROR: is/2: Arguments are not sufficiently instantiated
?- seq_start_end_len(Seq,4,3,X).
Seq = [],
X = 0 ;
ERROR: >/2: Arguments are not sufficiently instantiated

Это связано с использованием is/2 и >/2. Вы можете избежать этих ошибок, используя CLP (FD) :

:- use_module(library(clpfd)).         % <- new

seq_start_end_len([],_A,_B,0).
seq_start_end_len([A|As],A,B,C) :-
   C#>0,                               % <- change
   D #= A+B,                           % <- change
   E #= C-1,                           % <- change
   seq_start_end_len(As,D,B,E).

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

?- seq_start_end_len(Seq,X,3,10).
Seq = ['$VAR'('X'), _G1690, _G1693, _G1696, _G1699, _G1702, _G1705, _G1708, _G1711, _G1714],
'$VAR'('X')+3#=_G1690,
_G1690+3#=_G1693,
_G1693+3#=_G1696,
_G1696+3#=_G1699,
_G1699+3#=_G1702,
_G1702+3#=_G1705,
_G1705+3#=_G1708,
_G1708+3#=_G1711,
_G1711+3#=_G1714,
_G1714+3#=_G1838 ;
false.

Чтобы получить действительные числа, вам нужно ограничить диапазон X и пометить переменные в последовательности:

?- X in 1..4, seq_start_end_len(Seq,X,3,10), label(Seq).
X = 1,
Seq = [1, 4, 7, 10, 13, 16, 19, 22, 25, 28] ;
X = 2,
Seq = [2, 5, 8, 11, 14, 17, 20, 23, 26, 29] ;
X = 3,
Seq = [3, 6, 9, 12, 15, 18, 21, 24, 27, 30] ;
X = 4,
Seq = [4, 7, 10, 13, 16, 19, 22, 25, 28, 31] ;
false.

?- X in 1..4, seq_start_end_len(Seq,4,X,10), label(Seq).
X = 1,
Seq = [4, 5, 6, 7, 8, 9, 10, 11, 12, 13] ;
X = 2,
Seq = [4, 6, 8, 10, 12, 14, 16, 18, 20, 22] ;
X = 3,
Seq = [4, 7, 10, 13, 16, 19, 22, 25, 28, 31] ;
X = 4,
Seq = [4, 8, 12, 16, 20, 24, 28, 32, 36, 40] ;
false.

?- X in 1..4, seq_start_end_len(Seq,4,3,X), label(Seq).
X = 1,
Seq = [4] ;
X = 2,
Seq = [4, 7] ;
X = 3,
Seq = [4, 7, 10] ;
X = 4,
Seq = [4, 7, 10, 13] ;
false.

В версии CLP (FD) вы также можете задавать более общие запросы, например Какие существуют последовательности длиной от 4 до 6 с числами в диапазоне от 1 до 10? :

?- Len in 4..6, seq_start_end_len(Seq,S,E,Len), Seq ins 1..10, label(Seq).
Len = 4,
Seq = [1, 1, 1, 1],
S = 1,
E = 0 ;
Len = 4,
Seq = [1, 2, 3, 4],
S = E, E = 1 ;
Len = 4,
Seq = [1, 3, 5, 7],
S = 1,
E = 2 ;
.
.
.
Len = 6,
Seq = [9, 9, 9, 9, 9, 9],
S = 9,
E = 0 ;
Len = 6,
Seq = [10, 9, 8, 7, 6, 5],
S = 10,
E = -1 ;
Len = 6,
Seq = [10, 10, 10, 10, 10, 10],
S = 10,
E = 0 ;
false.

И вы получаете все 80 возможностей. Обратите внимание, насколько хорошо имя отражает реляционную природу предиката CLP (FD).

0 голосов
/ 29 апреля 2018

DCG может быть самым простым способом встроить оба хороших предложения @tas (+1) в ваш код.

print(_,_,0) --> [].
print(A,B,C) --> {C>0, D is A+B, E is C-1}, [A], print(D,B,E).

Тест:

?- phrase(print(4,3,10),S).
S = [4, 7, 10, 13, 16, 19, 22, 25, 28, 31] ;
false.

Редактировать

Предикаты высшего порядка, такие как foldl / 4 , также могут довольно компактно решить эту проблему (предшествуя идее @ user27815: +1):

initial_step_size_sequence(Initial,Step,Size,Sequence):-
    length(Sequence,Size),
    foldl({Step}/[A,B,C]>>(A=B,C is B+Step),Sequence,Initial,_).

Обратите внимание на «присваивание» элементам последовательности A=B (свободные переменные, созданные с помощью length / 2) и использование библиотеки ( yall ) для встраивания предиката.

0 голосов
/ 29 апреля 2018
equal(X,X).

initial_step_size_sequence(Initial,Step,Size,Sequence):-
    length([_H|List],Size),
    maplist(equal(Step),List),
    scanl(plus,List,Initial,Sequence).

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

?- initial_step_size_sequence(4,3,10,S).
S = [4, 7, 10, 13, 16, 19, 22, 25, 28, 31]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...