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

Предположим, у меня есть предикат, который иногда дает мне несколько выходных данных.Как это -

foo(Number, Out) :- Number < 10, Out = less_than_ten.
foo(Number, Out) :- Number > 0, Out = more_than_zero.

Как я могу получить все значения для Out, которые foo дает в другом предикате, имея в виду, что иногда он может давать один, а иногда и кратный (например, вlist)?

Edit - не совсем уверен, что ответы, которые я получил, отвечают на мой вопрос, поэтому я буду более конкретным.Взяв вышеупомянутый предикат, я мог бы выполнить запрос foo(5, Out). Это удовлетворяет обоим правилам, поэтому, если я запущу его в SWI-прологе, я получу это -

?- foo(5, Out).
Out = less_than_ten

Затем я могу ввести точку с запятойчтобы заставить пролог вернуться назад и найти другое решение -

?- foo(5, Out).
Out = less_than_ten ;
Out = more_than_zero.

Итак, если я выполнял этот предикат внутри другого, как мне получить все допустимые значения для Out, учитывая число = 5?

Ответы [ 3 ]

0 голосов
/ 29 ноября 2018

Если вы рассматриваете только целые числа, вы можете использовать CLP (FD).Тогда ваш предикат foo может выглядеть примерно так:

:- use_module(library(clpfd)).

foo(Nums) :-
   Nums ins 1..9.     % the numbers in the list Nums are 0 < X < 10

Вы можете использовать этот предикат, чтобы проверить, находится ли список чисел в нужном диапазоне:

   ?- foo([1,2,3,4,5]).
yes
   ?- foo([0,1,2,3,4,5]).
no
   ?- foo([1,2,3,4,5,10]).
no

Если вы хотитеиспользуйте его для генерации списков целых чисел в этом диапазоне, убедитесь, что Nums является списком, чтобы избежать ошибки создания экземпляра.Это можно сделать, добавив в запрос префикс длины цели / 2:

   ?- length(Nums,_), foo(Nums).
Nums = [] ? ;          % <- no number
Nums = [_A],           % <- one number
_A in 1..9 ? ;
Nums = [_A,_B],        % <- two numbers
_A in 1..9,
_B in 1..9 ? ;
Nums = [_A,_B,_C],     % <- three numbers
_A in 1..9,
_B in 1..9,
_C in 1..9 ?
.
.
.

Эти ответы состоят из остаточных целей (подробности см. В документации CLP (FD) ).Если вы хотите увидеть реальные цифры, вы должны добавить цель, чтобы пометить список:

   ?- length(Nums,_), foo(Nums), label(Nums).
Nums = [] ? ;
Nums = [1] ? ;
Nums = [2] ? ;
Nums = [3] ? ;
.
.
.
Nums = [1,1] ? ;
Nums = [1,2] ? ;
Nums = [1,3] ? ;
.
.
.
Nums = [9,9] ? ;
Nums = [1,1,1] ? ;
Nums = [1,1,2] ? ;
.
.
.
0 голосов
/ 29 ноября 2018

Только что нашел предикат, который отвечает на этот вопрос.Пролог имеет встроенный предикат bagof(Template, Goal, Bag), который объединяет аргумент Template предиката Goal с аргументом Bag (не уверен, что это правильный язык пролога!).Таким образом, в примере в вопросе используйте bagof(Out, foo(5, Out), Outputs)., и это объединит список решений для Out с Outputs.Выполнение запроса в SWI-прологе:

4 ?- bagof(Out, foo(5, Out), Outputs).
Outputs = [less_than_ten, more_than_zero].

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

0 голосов
/ 29 ноября 2018

Во-первых, предикат может быть успешным или неуспешным.

Более технически и отмечен в стандарте Пролога

В Прологе то, что вы бы назвали вызовом, являетсявыполнение.

Выполнение - это последовательность активаций, которые пытаются достичь цели.

В Прологе то, что вы думаете о возврате, указано как

Если активация BP прошла успешно, замените текущий активатор CCG активатором true, активация которого описана в (7.8.1 .l).

, поэтому значения передаютсявставка и извлечение состояний в стек.

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

Чтобы вызвать foo из bar, чтобы bar мог передать значение foo, было бы так:

bar :-
    foo(Passed_to_foo).

foo(Received_from_bar) :-
    % Do something with Received_from_bar.

Чтобы развернуть предыдущее и передатьзначение обратно от foo тo bar будет выглядеть так:

bar :-
    foo(Passed_to_foo,Received_from_foo).

foo(Received_from_bar,Passed_to_bar) :-
     % Do something with Received_from_bar
     % Generate/Compute Passed_to_bar

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

Чтобы не передавать значения в виде списка, просто передайте пустой список

[]

Чтобы передать одно значение в списке, просто поместите его в список и передайтеlist

[first_value]

Чтобы передать более одного значения, просто поместите их в список и передайте список

[first_value, second_value, third_value, ... ]

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

Базовый регистр

foo([],Result).

Рекурсивный регистр

foo([H|T],Result) :-
    % Do something with head of list `H`
    % Pass tail of list `T` back to foo for processing
    foo(T,Result).
...