However, I do not understand what they are aimed at?
Knowing what they are aimed at is, of course, impossible without asking them.
However, I think they seek to show that the Prolog is (more or less) untyped . append/3 documented as:
append(?List1, ?List2, ?List1AndList2)
List1AndList2 is a concatenation of List1 and List2 .
Thus, it is obvious that the three arguments are lists and a not a list. a not concatenation [] and a , since it can be assumed that two are not “concatenated”.
Now this is still running, because append/3 usually runs as:
append([],T,T). append([H|T],T2,[H|R]) :- append(T,T2,R).
So, if you give it append([],a,X). , it simply combines with the first sentence and unifies X = a .
The same “strange” behavior occurs with append([14],a,X) . Here X = [14|a] , which is also not a list. This is because the Prolog interpreter does not “know” what works with lists. For Prolog, [A|B] the same as any other functor.
A safer type type . It could be:
append([], [],[] ). append([H|T],T2,[H|R]) :- append(T,T2,R). append( [],[H|T],[H|R] ) :- append([],T,R).
Or more elegantly:
list([]). list([_|T]) :- list(T). append([], T,T ) :- list(T). append([H|T],T2,[H|R]) :- append(T,T2,R).
since here we check if the second argument is a list. However, the drawback is that now we will be append/3 in O (m + n), where m is the length of the first list and n is the length of the second list, while in the source code it only takes O (m) time. Also, note that Prolog will not raise a warning / error during parsing. He will not be able to add [] with a at the moment when you request them.
Do not check types leads to the fact that you have less guarantees if the program compiles / does not cause errors when passing it to the interpreter. This may be fine, but the problem may be that you are invoking some predicates in a way that they do not expect, which may cause errors later. This is why statically typed languages are sometimes used: they “guarantee” (at least to some extent) that if you cause a problem, there will be no such errors. Of course, this does not mean that the program cannot be mistaken in other things (or simply does not make sense). haskell , for example, is statically typed and has add:
(++) [] t2 = t2 (++) (h:t) t2 = h:((++) t t2)
The definition of "more or less" is the same, but Haskell will infer that the type (++) is (++) :: [a] -> [a] -> [a] . Since he knows the type of input and output of each function, he can do the calculus on it, so during compilation it will cause errors if you give (++) something other than a list.
Whether this is good, of course, is another question: dynamically typed programming languages are designed in such a way consciously, since this allows increasing flexibility.