李灏泽
李灏泽

Reputation: 19

How to evaluate a variable with string value?

My code does perfect with numbers, but error with single quotation. I'm trying to write a foldl function. When i do foldl1(concat, ['a','b'], X), it reports like "ERROR: Arithmetic: 'ab/0' is not a function". what is the problem? prolog does not allow using is with string?

foldl1(P, [H], X) :-
    X is H.

foldl1(P, [H|T], X) :-
    foldl1(P, T, Y),
    call(P, H, Y, Z),
    X is Z.

Upvotes: 1

Views: 119

Answers (2)

CapelliC
CapelliC

Reputation: 60014

is/2 evaluates the arithmetic expression to the right, and unifies the result with the term to the left. Unification is also performed against the head' arguments, so you can write a simplified foldl1/3 like

foldl1(_, [H], H).
foldl1(P, [H|T], Z) :-
    foldl1(P, T, Y),
    call(P, H, Y, Z).

test:

?- foldl1(plus,[1,2,3],R).
R = 6 ;
false.

?- foldl1(concat,[1,2,3],R).
R = '123' ;
false.

I would place a cut after the recursion base, since [H] and [H|T] where T=[] overlap, to avoid any last call - that would anyway fail - on eventual backtracking, like the redo induced by me, inputting ; after the expected first answer while the interpreter waits for my choices. After the cut (hope you can easily spot where to place it) we get:

?- foldl1(plus,[1,2,3],R).
R = 6.

?- foldl1(concat,[1,2,3],R).
R = '123'.

Now the interpreter 'knows' there are no more answers after the first...

Upvotes: 2

Paulo Moura
Paulo Moura

Reputation: 18663

It's also possible to implement a foldl1/3 predicate using first-argument indexing to avoid spurious choice-points without cuts and that is also tail-recursive. From the Logtalk library meta object:

:- meta_predicate(foldl1(3, *, *)).
foldl1(Closure, [Head| Tail], Result) :-
    fold_left_(Tail, Closure, Head, Result).

fold_left_([], _, Result, Result).
fold_left_([Arg| Args], Closure, Acc, Result) :-
    call(Closure, Acc, Arg, Acc2),
    fold_left_(Args, Closure, Acc2, Result).

Sample calls:

?- meta::foldl1(plus,[1,2,3],R).
R = 6.

?- meta::foldl1(concat,[1,2,3],R).
R = '123'.

Upvotes: 1

Related Questions