tags:

views:

160

answers:

2

I tried to write functor inbuilt in Prolog. This is my version:

lenlist(L,N) :- lenlist(L,0,N).
lenlist([],N,N).
lenlist([_|T],P,N) :- P1 is P+1 , lenlist(T,P1,N).

functor1(Term,F,N) :- Term =.. [F|Args] , lenlist(Args,N).

Here is a sample execution of prolog inbuilt functor

?- functor(Term,f,6).  
Term = f(_G247, _G248, _G249, _G250, _G251, _G252)

Now if i execute the same querry with functor1 i get an exception

?- functor1(Term,f,6).
ERROR: =../2: Arguments are not sufficiently instantiated
   Exception: (8) _G180=..[f|_G248] ? creep

whats wrong with the funtor1 function I wrote?

+3  A: 

The problem is that Args is not yet instantiated for =.. . Try putting lenlist/3 before it.

BTW, you could also use the built-in length/2.

starblue
functor1(Term,F,N) :- length(Args,N) , Term =.. [F|Args],!. ---This works
bakore
Well I had to put a cut , for it not go and seek other solution.But this ideally should return with "no" when pressed for more solutions. Without cut it goes out of stack
bakore
+3  A: 

starblue is correct, but in order to write your version of functor1/3 properly, I recommend that you consider the 'modes' it requires:

  1. Inspect an existing term (i.e., not a variable) for it's functor/arity.
  2. Build a term (assigning it to a variable) from a functor/arity description.
  3. All other modes are irrelevant/incorrect.

With these three cases in mind, try the following. First, case (1): extract the Functor and Arity from an existing Term:

functor1(Term, Functor, Arity) :-
    \+ var(Term), !,
    % inspect existing term
    Term =.. [Functor|ArgList],
    length(ArgList, Arity).

Note that we exclude other cases if the Term argument is not a variable with the cut (!). Secondly, case (2): construct a Term from a Functor and an Arity:

functor1(Term, Functor, Arity) :-
    var(Term), 
    atom(Functor),
    number(Arity), !,
    % build a term
    length(ArgList, Arity),
    Term =.. [Functor|ArgList].

Note that the mode checking performed by the subgoals prior to the cut (!) encapsulate the guard (precondition) for this case. Finally, all other cases (i.e., those where we need to construct a term, but don't have a functor, arity or either) are invalid (3):

functor1(_Term, _Functor, _Arity) :-
    throw('Arguments are not sufficiently instantiated.').

Alternatively, for this last case, this whole clause can be omitted to achieve the behavior that functor/1 returns false for the remaining argument bindings it will cover.

Also note that this version relies on built-ins length/2, var/1, number/1 and atom/1 (among others), which are present in SWI-PROLOG.

sharky
+1 for attention to detail. This is seriously an *excellent* answer.
bcat