Did you know ... | Search Documentation: |
Predicate ,/2 |
:- table c/2. c(F,T) :- c(F,I), c(F,T). c(F,T) :- c(T,F). c(a,b). c(b,c). c(e,f).
Now populate the table for c(a,T)
:
?- c(a,T). T = a ; ...
Now you can enumerate the table's content using get_call/2 and get_returns/3:
?- get_call(c(a,T), Trie, Template), get_returns(Trie, Template). T = a ; ...
Note that this gives the same results as just calling c(a,T)
. The table
inspection predicates are mostly used for debugging.
is_odd(I) :- 0 =\= I mod 2.
?- numlist(1, 6, List), include(is_odd, List, Odd). List = [1, 2, 3, 4, 5, 6], Odd = [1, 3, 5].
?- length(L, 3), maplist(between(0, 1), L). L = [0, 0, 0] ; L = [0, 0, 1] ; L = [0, 1, 0] ; L = [0, 1, 1] ; L = [1, 0, 0] ; L = [1, 0, 1] ; L = [1, 1, 0] ; L = [1, 1, 1].
?- length(L, 5), maplist(=(foo), L). L = [foo, foo, foo, foo, foo].
Normally used to update the value associated with a key. For example, if the value is a count that must be incremented, do
inc_count(Key, A0, A) :- get_assoc(Key, A0, C0, A, C), !, C is C0+1. inc_count(Key, A0, A) :- put_assoc(Key, A0, 1, A).
With the help of library(csv) and library(http/json), we read a CSV file and use the column names in the first row to emit JSON.
For this example, we use the file weather.csv
:
city,temp_lo,temp_hi,prcp,date San Francisco,46,50,0.25,1994-11-27 San Francisco,43,57,0,1994-11-29 Hayward,37,54,,1994-11-29
The script csv_to_json.pl
reads the CSV from standard input or from
the file provided as the first argument of the script. It converts
the contents to a list of dicts, then writes this as JSON to standard
output:
:- initialization(main, main). :- use_module(library(csv)). :- use_module(library(http/json)). main :- ( current_prolog_flag(argv, [CSV_file|_]) -> csv_read_file(CSV_file, CSV, []) ; csv_read_stream(current_input, CSV, []) ), CSV = [Colnames|Rows], Colnames =.. [row|Names], maplist(row_dict(Names), Rows, Dicts), json_write_dict(current_output, Dicts, [null('')]). row_dict(Names, Row, Dict) :- Row =.. [row|Fields], pairs_keys_values(Data, Names, Fields), dict_create(Dict, _, Data).
The null('')
option to json_write_dict/3 is necessary to convert the
empty "prcp" field in the last row to a missing value represented as
null
in the JSON output.
This is how we can use it to convert weather.csv
to JSON:
$ swipl csv_to_json.pl weather.csv [ { "city":"San Francisco", "date":"1994-11-27", "prcp":0.25, "temp_hi":50, "temp_lo":46 }, { "city":"San Francisco", "date":"1994-11-29", "prcp":0, "temp_hi":57, "temp_lo":43 }, { "city":"Hayward", "date":"1994-11-29", "prcp":null, "temp_hi":54, "temp_lo":37 } ]
file_lines(File, Lines) :- setup_call_cleanup(open(File, read, In), stream_lines(In, Lines), close(In)). stream_lines(In, Lines) :- read_string(In, _, Str), split_string(Str, "\n", "", Lines).
This loads all lines to memory as strings. If we use the Unix dictionary words:
?- file_lines("/usr/share/dict/words", Lines). Words = ["A", "a", "aa", "aal", "aalii", "aam", "Aani", "aardvark", "aardwolf"|...].
file_line(File, Line) :- setup_call_cleanup(open(File, read, In), stream_line(In, Line), close(In)). stream_line(In, Line) :- repeat, ( read_line_to_string(In, Line0), Line0 \== end_of_file -> Line0 = Line ; !, fail ).
This will backtrack over consecutive lines in the input. If we use the Unix dictionary words:
?- file_line("/usr/share/dict/words", Word). Word = "A" ; Word = "a" ; Word = "aa" ; Word = "aal" ; % and so on
This doesn't load all lines to memory, so it can be used with very large files.
This shows how to convert almost any "string" of 0s and 1s to an integer.
It takes advantage of the built-in term reading, thus avoiding an explicit loop and arithmetic.
binary_string_to_int(Str, Int) :- ( ( string(Str) ; atom(Str) ) -> atomics_to_string(["0b", Str], Literal) ; is_list(Str) -> atomics_to_string(["0b"|Str], Literal) ; type_error(string_type, Str) ), catch(term_string(Int, Literal, []), error(syntax_error(_), _), type_error(string_of_0s_and_1s, Str)).
?- binary_string_to_int('101', X). X = 5. ?- binary_string_to_int([0, 0, 1, 0, 1], X). X = 5. ?- binary_string_to_int(["1", "1", "0"], X). X = 6.
The append/3 predicate can be used to split and join lists. We can combine that to realise substituting all appearances of a sublist into another as illustrated below.
append(This, After, Rest)
creates a pattern from This,
i.e., the list Rest starts with This.append(Before, Rest, MyStr)
matches the pattern against the
input list. On a match we commit (!). Now Before is the
input list before the match and After is the input list
after the match.subst(This, That, MyStr, Result) :- append(This, After, Rest), append(Before, Rest, MyStr), !, subst(This, That, After, AfterResult), append([Before,That,AfterResult], Result). subst(_, _, S, S).
?- portray_text(true). true. ?- subst(`this`,`that`,`athishellothis`,R). R = `athathellothat`.
word_frequency_count(Words, Counts) :- maplist(downcase_atom, Words, LwrWords), msort(LwrWords, Sorted), clumped(Sorted, Counts).
?- word_frequency_count([a,b,'A',c,d,'B',b,e], Counts). Counts = [a-2, b-3, c-1, d-1, e-1].