How do I turn the outputs of a function into a lis

2019-08-05 04:16发布

I have a function that outputs names that fit a specific constraint. This function is fine.

But I need to use that function to make another function that turns the outputs of the former function into a list. Being a complete beginner with Prolog, I have no clue how to do this.

My problem is that I don't know how to iterate over the outputs to append it to an accumulator. The function which outputs names does so, then I press ";" or SPACE and it outputs the next answer until it's out of answers. I figure this means I have to make multiple calls to the function then append it. But I don't know how many times I need to call it, since I can't iterate over it like a list with [Head|Tail].

Here's what I have so far(although it's probably wrong):

%p1(L,X) determines if chemicals in List X are in any of the products and stores those        products in L
p1(L,X) :- p1_helper(L,X,[]).
p1_helper(L,X,Acc) :- has_chemicals(A,X),append(Acc,[A],K),L=K, p1_helper(L,X,K).

function that outputs names with query has_chemicals(X,[List of Chemicals]).:

%has_chemicals(X,Is) determines if the chemicals in List Is are in the chemical list of X.
has_chemicals(X,Is) :- chemicals(X,Y), hc(Y,Is).
%hc(X,Y) determines if elements of Y are in elements of X.
hc(Y,[]).
hc(Y,[C|D]) :- isin(C,Y), hc(Y,D).

Any help is appreciated.

标签: list prolog
3条回答
Evening l夕情丶
2楼-- · 2019-08-05 05:01

But I need to use that function to make another function that turns the outputs of the former function into a list. Being a complete beginner with Prolog, I have no clue how to do this.

findall(+Template, :Goal, -Bag): Creates a list of the instantiations Template gets successively on backtracking over Goal and unifies the result with Bag.

For example, how to collect all odd numbers from 1 to 15:

odd( X ) :-
    X rem 2 =:= 1.

We can get all that odds one-by-one.

?- between( 1, 15, X ), odd( X ).
X = 1 ;
X = 3 ;
X = 5 ;
X = 7 ;
X = 9 ;
X = 11 ;
X = 13 ;
X = 15.

And we can collect them into a list:

?- findall(X, (between( 1, 15, X ), odd( X )), List).
List = [1, 3, 5, 7, 9, 11, 13, 15].
查看更多
做自己的国王
3楼-- · 2019-08-05 05:05

I encourage you to visit this page especially if you use swi-prolog.

There are 4 predicates that do what you want : findall/3, findall/4, bagof/3 and setof/3.

To summarize, here is the test predicate I'll be working with :

test(0, 3).
test(1, 3).
test(2, 5).
test(3, 4).

First, the simplest, findall/3 and findall/4 :

?- findall(C, test(X, C), Cs).
Cs = [3, 3, 5, 4].

?- findall(C, test(X, C), Cs, TailCs).
Cs = [3, 3, 5, 4|TailCs].

They just return all the alternatives, with duplicates, without sorting, without binding the other free variables, as a normal list for findall/3 and difference list for findall/4. both findalls predicates succeed when the list is empty.

Then, bagof. Basically, bagof/3 works as findall/3 but binds free variables. That means that the same query than above but with bagof/3 returns :

?- bagof(C, test(X, C), Cs).
X = 0,
Cs = [3] ;
X = 1,
Cs = [3] ;
X = 2,
Cs = [5] ;
X = 3,
Cs = [4].

By telling bagof/3 not to bind all the free variables, you obtain findall/3 :

?- bagof(C, X^test(X, C), Cs).
Cs = [3, 3, 5, 4].

Still you have to note that bagof/3 fails when the result is empty, where findall/3 doesn't.

Finally, setof/3. It's basically bagof/3 but with the results sorted and no duplicates :

?- setof(C, X^test(X, C), Cs).
Cs = [3, 4, 5].
查看更多
贪生不怕死
4楼-- · 2019-08-05 05:07

I think you are looking for a way to capture the output of isin/2. Then you can use the builtin with_output_to/2, and combine it with findall/3, as suggested by other answers.

查看更多
登录 后发表回答