简体   繁体   中英

Prolog - unifying two lists with/without variables

This Prolog code returns:

?- [a,b,c,d]  =  [a|[b,c,d]].

true

and this one

?- [X,Y] = [a|[b,c,d]].

returns false.

I am not totally grasping why [X, Y] is false. Trace is not helpful here. I would expect the following assignment to hold

X = a
Y = [b,c,d]

and the statement be true.

What does | do besides splitting on head and tail?

A list in Prolog is implemented as a linked list of functors. If you write a list like [a, b, c, d] . it looks in reality like:

+-------+
| (|)/2 |
+---+---+   +-------+
| o | o---->| (|)/2 |
+-|-+---+   +---+---+   +-------+
  v         | o | o---->| (|)/2 |
  a         +-|-+---+   +---+---+   +-------+
              v         | o | o---->| (|)/2 |
              b         +-|-+---+   +---+---+   
                          v         | o | o----> []
                          c         +-|-+---+
                                      v
                                      d

or in Prolog notation [a | [b | c | [d | [] ] ] ] [a | [b | c | [d | [] ] ] ] [a | [b | c | [d | [] ] ] ] . The comma-separated list is syntactical sugar : if you write [a, b, c, d] , the Prolog interpreter converts it to a representation as above.

Since [b, c, d] is equal to:

[ b | [ c | [ d | [] ] ] ]

and thus [ a | [b, c, d] ] [ a | [b, c, d] ] is thus equal to

[a | [b | c | [d | [] ] ] ]

But the list [X, Y] is just equal to

[X, Y] == [ X | [ Y | [] ] ]

or in a structural way:

+-------+
| (|)/2 |
+---+---+   +-------+
| o | o---->| (|)/2 |
+-|-+---+   +---+---+
  v         | o | o----> []
  X         +-|-+---+
              v
              Y

If we then match it with [a | [b | c | [d | [] ] ] ] [a | [b | c | [d | [] ] ] ] [a | [b | c | [d | [] ] ] ] this means the "outer" shell can be matched, so X = a , but then Y = b , and [] = [ c | [ d | [] ] ] [] = [ c | [ d | [] ] ] [] = [ c | [ d | [] ] ] . The last part does not match, and thus it returns false . The X and Y are thus not the problem. The problem is that [] is a constant, and it does not match with the functor that represents [ c | [d] ] [ c | [d] ] .

If we would for example unify [ X | Y ] == [a, b, c, d] [ X | Y ] == [a, b, c, d] we get:

?- [ X | Y ] = [a, b, c, d].
X = a,
Y = [b, c, d].

So to conclude, one can say that | itself "does" nothing. It is a functor, just like f(1, 2) . In Lisp they used cons [wiki] for this, and nil for the empty list. So [1, 4, 2, 5] looks in Lisp like cons 1 (cons 4 (cons 2 (cons 5 nil))) , or in Prolog it would look like cons(1, cons(4, cons(2, cons(5, nil)))) . It is only a bit cumbersome to write. In fact the comma separated notation is more the "magic" part. Prolog just performs unification for lists, just like it does for other functors and constants.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM