title: prolog, changing atoms in expression
body: <p>my task is to write a predicate <code>subst(T,A,V,R)</code> that changes all occurences of atom <code>A</code> in expression <code>T</code> to atom <code>V</code> and the result is presented as <code>R</code>.</p>
  
  <p>For instance:</p>
  
  <pre><code>subst(object(one, two),one,three,R). //R=object(three,two).
  susbt(a+1,a,2,R). //R=2+1.
  </code></pre>
  
  <p>It could be easy with the approach: I change the expression to list using <code>T=..L</code>, then I compare every element of <code>L</code> with <code>A</code> and if they're the same, I can change it to <code>V</code>. In the end, I can reverse the very first action (to get the expression again), but I don't know how to deal with situation like:
  <code>subst((a+1)*(b+3),a,2,W)</code>. // ?</p>
  
  <p>Starting with something like <code>T=..L</code> I can get <code>[*,a+1,b+3]</code>, but now if I would like to change <code>a</code> to <code>2</code>, I can't check every consecutive item of <code>L</code> because some of them are not simple atoms/numbers. Now my question is, is there any built-in predicate to check if the element in a list is like: <code>a</code>, <code>1</code>, etc., but not <code>a+1</code>? I mean if I wouldn't like to check first if it's atom or not and later if it's number of not.</p>
  
  <p>Or maybe there is some easier approach to that matter?</p>
  
  <p><strong>EDIT1:</strong>
  Thanks for comments. I have so far:</p>
  
  <pre><code>subst(T,A,V,R):-T=..L,make_simple(L,L1),replace(L1,A,V,L2),to_exp(L2,R).
  
  make_simple([],[]).
  make_simple([H|T],[H|W]):-atom(H),make_simple(T,W),!.
  make_simple([H|T],[H|W]):-number(H),make_simple(T,W),!.
  make_simple([H|T],[W1|W2]):- \+atom(H),\+number(H),H=..H1,make_simple(H1,W1),make_simple(T,W2).
  
  replace([],_,_,[]).
  replace([A|T],A,V,[V|W]):- replace(T,A,V,W),!.
  replace([H|T],A,V,[H|W]):- H\=A,\+is_list(H),replace(T,A,V,W),!.
  replace([H|T],A,V,[W1|W2]):-H\=A, is_list(H),replace(H,A,V,W1),replace(T,A,V,W2),!.
  
  to_exp([],[]).
  to_exp([H|T],[H|W]):- \+is_list(H),to_exp(T,W),!.
  to_exp([H|T],[W1|W2]):- is_list(H), (what next?)
  </code></pre>
  
  <p>Unfortunately, I don't know how to put ap those pieces together now in <code>to_exp</code> part. Especially, when it's like:</p>
  
  <pre><code>to_exp([*,[+,a,1],[-,3,b]]).
  </code></pre>
  
  <p>or even worse:</p>
  
  <pre><code>to_exp([*,[+,[*,4,2],1],[-,3,b]]).
  </code></pre>
  
  <p>What I mean, if an element of an outer list is a list, I don't know how to identify that it's exactly list of three elements, where each of them is an atom/number. Any tips?:)</p>
  
  <p><strong>EDIT2</strong></p>
  
  <p>Okay, I was told that it's getting far too complicated. Maybe, but I'm new in Prolog and I'm using only tools/techniques that I've learned so far, because the tasks I am supposed to do are constructed this way. Of course, there must be simpler ways, like that one suggested by @mat, yet I haven't learned about <code>dif</code> or <code>maplist</code> predicates so far. This is why I've decided to continue this one this way. </p>
  
  <p>I've found out that there is no need to check for <code>atom</code> and <code>number</code> separately. There's <code>atomic/1</code> that returns true if a term is number, atom, or en empty list (so the problem mentioned by @mat about SWI-Prolog doesn't seem to matter that much). Following that, I've changed previous predicates and I've finished <code>to_exp</code> as:</p>
  
  <pre><code>subst(T,A,V,R):-T=..L,make_simple(L,L1),replace(L1,A,V,L2),to_exp(L2,R).
  
  make_simple([],[]).
  make_simple([H|T],[H|W]):-atomic(H),make_simple(T,W),!.
  make_simple([H|T],[W1|W2]):- \+atomic(H),H=..H1,make_simple(H1,W1),make_simple(T,W2),!.
  
  replace([],_,_,[]).
  replace([A|T],A,V,[V|W]):- replace(T,A,V,W),!.
  replace([H|T],A,V,[H|W]):- H\=A,\+is_list(H),replace(T,A,V,W),!.
  replace([H|T],A,V,[W1|W2]):-H\=A, is_list(H),replace(H,A,V,W1),replace(T,A,V,W2),!.
  
  to_exp([],[]).
  to_exp([Z,H1,H2],L):-atomic(H1),atomic(H2),L=..[Z,H1,H2],!.
  to_exp([Z,H1,H2],L):- \+atomic(H1),atomic(H2),to_exp(H1,W1),L=..[Z,W1,H2].
  to_exp([Z,H1,H2],L):- atomic(H1),\+atomic(H2),to_exp(H2,W1),L=..[Z,H1,W1].
  to_exp([Z,H1,H2],L):- \+atomic(H1),\+atomic(H2),to_exp(H1,W1),to_exp(H2,W2),L=..[Z,W1,W2].
  </code></pre>
  
  <p>Now, it works both for functors and arguments, simple and nested ones.
  Anyway, thanks for the influence, I definitely will consider using <code>dif</code> and <code>maplist</code> in the future. Cheers:)</p>