Higher-order predicates
call/N, maplist, foldl, filters, and lambdas.
In Prolog, code is data. call/N takes a goal (or part of one) and runs it, adding extra arguments:
?- call(write, hello)?- G = format("~w and ~w~n"), call(G, [a, b])?- call(plus(1), 2, X)plus(1) is a partial goal; call(plus(1), 2, X) appends the arguments and runs plus(1, 2, X). This is currying, and it makes the list-processing predicates below possible.
maplist: apply a relation to every element
double(X, Y) :- Y is X * 2.
even(X) :- 0 is X mod 2.
add(X, Acc0, Acc) :- Acc is Acc0 + X.?- maplist(double, [1, 2, 3], L)?- maplist(double, L, [2, 4, 6])?- maplist(succ, L, [2, 3, 4])?- maplist(atom, [a, b, c])?- maplist([X, Y, Z]>>(Z is X + Y), [1, 2, 3], [10, 20, 30], Sums)maplist/3 also works backwards when the relation does (succ/2 does; our double/2, built on is, can't, as the error above shows).
Filtering and folding
?- include(even, [1, 2, 3, 4, 5, 6], L)?- exclude(even, [1, 2, 3, 4, 5, 6], L)?- partition(even, [1, 2, 3, 4, 5], In, Out)?- foldl(add, [1, 2, 3, 4], 0, Sum)?- foldl([X, A0, A]>>(A is max(X, A0)), [3, 9, 2], 0, Max)foldl(Goal, List, Start, Result) threads an accumulator through the list: Goal is called as call(Goal, Element, AccBefore, AccAfter).
Lambdas with >>
Writing a helper predicate for every tiny operation is tedious. The yall library lets you write anonymous predicates inline:
[X1, X2, ...] >> Body
Parameters are listed before >>. Variables from the surrounding clause are visible in the body, if they're already bound when the lambda runs:
scale(K, List, Scaled) :- maplist([X, Y]>>(Y is X * K), List, Scaled).
only_big(Min, List, Big) :- include([X]>>(X >= Min), List, Big).?- scale(10, [1, 2, 3], L)?- only_big(5, [3, 8, 5, 1, 9], L)Building goals at run time
=.. and call/1 let a program assemble and execute goals dynamically:
?- Goal =.. [format, "~w squared is ~w~n", [4, 16]], call(Goal)?- forall(member(Op, [+, -, *]), (G =.. [Op, 6, 3], X is G, format("~w = ~w~n", [G, X])))Exercise: Sum of squares
Write sum_of_squares(List, Sum) using maplist (with a lambda or helper) and sum_list. For example sum_of_squares([1, 2, 3], S) gives S = 14.