I have this data (the data is read from csv and it has to look like this, aka. a list of terms, rather than as plain terms defined in database):
Rows = [row('A', 150), row('B', 300), row('C', 50)].
Now I wish to filter them by value, what I wish to do is like this (directly as query):
?- findall(Row, (member(row(Name, Value), Rows), Value > 50), Filtered).
However this won't work and gives:
?- Rows = [row('A', 150), row('B', 300), row('C', 50)],
findall(Row, (member(row(Name, Value), Rows), Value > 50), Filtered).
Rows = [row('A', 150), row('B', 300), row('C', 50)],
Filtered = [_, _].
At the moment the only way to do it is to put them inside a file:
% Code.pl
% Have to provide this as a predicate
filter(Row, Rows) :-
Row = row(_, Value),
member(Row, Rows),
Value > 50.
% Also wanted to declare the following
% Neither works:
% data = [row('A', 150), row('B', 300), row('C', 50)].
% Rows = [row('A', 150), row('B', 300), row('C', 50)].
Then I can do:
?- Rows = [row('A', 150), row('B', 300), row('C', 50)], findall(Row, filter(Row, data), Filtered).
# Or alternatively, wished to do:
?- findall(Row, filter(Row, data), Filtered).
On the other hand, while drafting this example I came across this problem:
% Wanted to put data directly inside code file, then query directly
% Neither works:
% data = [row('A', 150), row('B', 300), row('C', 50)].
% Rows = [row('A', 150), row('B', 300), row('C', 50)].
I have two questions regarding syntax:
Rows = [row('A', 150), row('B', 300), row('C', 50)], findall(Row, (member(row(Name, Value), Rows), Value > 50), Filtered).
Remark:
- How to put the data directly inside the code file (for the purpose of this example), as a list of terms?
Either as a fact:
rows([row('A', 150), row('B', 300), row('C', 50)]).
then rows(Rows)
, or as individual facts:
row('A', 150).
row('B', 300).
row('C', 50).
and then a findall to gather those up.
- For the query, is there anyway to achieve what I wanted without having to put everything inside a script file?
Your findall line does not declare what Row
is:
?- Rows = [row('A', 150), row('B', 300), row('C', 50)],
findall(Row, (member(row(Name, Value), Rows), Value > 50), Filtered).
^
|
|_ this is an uninitialized variable,
so your output is Filtered = [_, _]
a list of two unintialized variables.
so you could fix it as Paulo Moura answers, or you could do:
?-Rows = [row('A', 150), row('B', 300), row('C', 50)],
findall(row(Name, Value), (member(row(Name, Value), Rows), Value > 50), Filtered).
Filtered = [row('A',150), row('B',300)]
Or you could use include/3
with a test predicate:
row_value_test(row(_, Value)) :-
Value > 50.
?- Rows = [row('A', 150), row('B', 300), row('C', 50)],
include(row_value_test, Rows, Filtered).
Filtered = [row('A',150), row('B',300)]
or yes, you could do that inline with a lambda:
?- Rows = [row('A', 150), row('B', 300), row('C', 50)],
include([row(_,V)]>>(V>50), Rows, Filtered).
Filtered = [row('A',150), row('B',300)]