Search code examples
prologiso-prolog

Get index of a Term's argument in Prolog


I need to get the index of a term's argument in Prolog. Predicate arg/3 seems to do the opposite of what I need:

arg(Index, Term, Value).

arg/3 fails if Index is a variable, so it's not possible to get the index of a given value and term. You guys know any other way to achieve this (I can't use external libraries)?

An example of the expected behaviour would be:

?- arg_(Index, regs(a,b,c), c).
Index = 3

Solution

  • Not all Prolog implementations seem to behave like SWI-Prolog does when the index is a variable. Its behavior might be an extension to the standard.

    Here is what GNU Prolog 1.4.5 does:

    | ?- arg(Index,s(a,b,c,d),V).
    uncaught exception: error(instantiation_error,arg/3)
    | ?- arg(Index,regs(a,b,c),c).
    uncaught exception: error(instantiation_error,arg/3)
    

    So you'll have to backtrack over the valid indices yourself. You can use functor/3 to find out how many arguments there are:

    | ?- Term = regs(a,b,c), functor(Term, _Functor, Arity).
    
    Arity = 3
    Term = regs(a,b,c)
    
    yes
    

    And many Prologs (including GNU Prolog) have a between/3 predicate for enumerating integers in a range:

    | ?- between(1, 4, N).
    
    N = 1 ? ;
    
    N = 2 ? ;
    
    N = 3 ? ;
    
    N = 4
    
    (1 ms) yes
    

    So overall you can do:

    | ?- Term = regs(a,b,c), functor(Term, _Functor, Arity), between(1, Arity, Index), arg(Index, Term, Value).
    
    Arity = 3
    Index = 1
    Term = regs(a,b,c)
    Value = a ? ;
    
    Arity = 3
    Index = 2
    Term = regs(a,b,c)
    Value = b ? ;
    
    Arity = 3
    Index = 3
    Term = regs(a,b,c)
    Value = c
    
    yes