The unification algorithm is simple
- if both sides are constants (numbers, strings, atoms, etc.) the result unifies it it is the same one
- if one side is a variable, we add the subtitution of this variable by the other side
- if both sides are functions, it unifies if this is the same function (same name) and same parity (number of parameters), then unify recursively parameters.
With your examples:
f(g(a,X),g(Y,Y)) = f(g(a,b),g(f(a),f(Z)))
3rd case, same function (f) and same arity (2). So you have to unify parameters:
- g(a,X) = g(a,b)
- g(Y,Y) = G(f(a), f(Z))
g(a,X) unifies with g(a,b) because this is the same function (g) same arity (2). a = a unifies (case 1), X = b unifies (case 2) with substitution {X/b}
G(Y,Y) unifies with G(f(a), f(Z)) because this is the same function (g) same arity (2). then Y=f(a) => substitution {Y/f(a)} and Y=f(Z) => f(a) unifies with F(Z) {Z/a}
In the end you get o = {X/b, Y/f(a), Z/a}
- f(cons(cons(a,b))) = f(cons(cons(a,nil)))
The same applies here. Same function (f) same arity (1). Unify cons(cons(a,b)) = cons(cons(a,nil))
Same function (cons) same arity (1). Unify cons(a,b) = cons(a,nil)
Same function (cons), same arity (2). Unify a=a (OK), b=nil => NO
This does not unify.