A recursive approach would be straight-forward and would work. I recommend figuring that one out. But here's a fun alternative:
repl(X, N, L) :-
length(L, N),
maplist(=(X), L).
If N
is instantiated, then length(L, N)
will generate a list of length N
of just "blanks" (don't care terms). Then maplist(=(X), L)
will unify each element of L
with the variable X
.
This gives a nice, relational approach and yields sensible results in the general case:
| ?- repl(X, N, L).
L = []
N = 0 ? ;
L = [X]
N = 1 ? ;
L = [X,X]
N = 2 ? ;
| ?- repl(X, N, [x,x,x]).
N = 3
X = x
yes
...
To figure out a recursive case, think about what your base case looks like (it would be repl
with a count of 0
- what does the list look like then?). In the recursive case, think in terms of:
repl(X, N, [X|T]) :- ...
Meaning: The list [X|T]
is the element X
repeated N
times if.... Figure out if what? If your base case is length 0
, then your recursion is probably going to describe the repl
of a list of length N
in terms of the repl
of a list of length N-1
. Don't forget in this recursive rule to ensure N > 0
to avoid infinite recursion on backtracking. If you don't need the predicate to be purely relational and assume N
is instantiated, then it can be fairly simple.
If you make a simple recursive version, you can "wrap" it in this predicate to make it work with variable N
:
repl(X, N, L) :-
length(L, N),
simple_recursive_repl(X, N, L).
...
Because length/2
is relational, it is much more useful than just providing the length o a given list. When N
and L
are not instantiated, it becomes a generator of variable lists, starting at length 0
. Type, length(L, N).
at the Prolog prompt and see what happens.