Skip to content
Meta-Programming
step 1/4

Reading — step 1 of 4

Learn

~2 min readDCG, CLP, Meta-Programming

Prolog code IS data. Programs can construct, inspect, and execute terms — making meta-programming easy.

call/N

The most common meta-call. call(Goal) runs Goal as if it were called directly:

?- G = write(hello), call(G).
hello
G = write(hello).

?- call(write, hello).        %% same — multi-arity call
hello

With extra args, call/N adds them: call(Pred, Arg1, Arg2) is Pred(Arg1, Arg2).

Higher-order patterns

%% maplist applies a goal to each list element
?- maplist(succ, [1, 2, 3], L).
L = [2, 3, 4].

?- maplist([X, Y]>>(Y is X * 2), [1, 2, 3], L).
L = [2, 4, 6].             %% lambda-like syntax

%% Filter
?- include([X]>>(X > 5), [1, 5, 10, 15], L).
L = [10, 15].

%% Fold
?- foldl([X, Acc, NewAcc]>>(NewAcc is Acc + X), [1,2,3,4,5], 0, S).
S = 15.

Inspecting terms

?- functor(foo(a, b, c), Name, Arity).
Name = foo, Arity = 3.

?- arg(2, foo(a, b, c), Arg).
Arg = b.

?- T =.. [foo, a, b, c].   %% "univ" — convert to/from list
T = foo(a, b, c).

?- foo(a, b, c) =.. L.
L = [foo, a, b, c].

Building goals at runtime

run_op(Op, X, Y, R) :-
    Goal =.. [Op, X, Y, R],
    call(Goal).

?- run_op(plus, 3, 4, R).
R = 7.

This builds the goal plus(3, 4, R) from parts and calls it.

assert for code generation

:- dynamic(square/2).

build_squares(N) :-
    forall(between(1, N, X),
           ( Sq is X * X,
             assertz(square(X, Sq))
           )).

?- build_squares(5).
?- square(3, S).
S = 9.

Generated facts at runtime — useful for caching, derived data, dynamic rule sets.

apply style

:- use_module(library(yall)).        %% SWI lambda library

transform(Pred, [X|T], [Y|TT]) :-
    call(Pred, X, Y),
    transform(Pred, T, TT).
transform(_, [], []).

?- transform([X, Y]>>(Y is X * 2), [1, 2, 3], R).
R = [2, 4, 6].

clause/2 for introspection

?- clause(member(X, [1, 2, 3]), Body).
%% returns the body of one matching clause

Useful for debuggers, profilers, theorem provers.

Practical use

  • Generic predicates — work with any predicate via call/N
  • DSL implementation — meta-interpret a custom language
  • Theorem provers — manipulate logic formulas as terms
  • Code analysis — walk and rewrite source clauses

Prolog's homoiconic nature (code = data) plus unification = a metaprogramming sweet spot.

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…