Dot notation in scheme

Note: this is cannibalized from an answer to Recursive range in Lisp adds a period?, which is really asking a different question. However, the explanation of how pairs are printed is the same. The rest of the answer is different.

Your question exhibits a bit of misunderstanding, but I think we can clear it up.

The first [argument to cons] could be a symbol, or a list, it
doesn’t matter. But specially the second element must be a symbol, if
it is not, may be a list for instance, then we can’t create a pair
with built-in cons procedure.

This is not correct. You can call cons with whatever arguments you like, and you will always get back a cons cell whose car is the same as the first argument to cons, and whose cdr is the same as the second argument to cons. That is, the only thing that’s important about cons is that it satisfies the equations

(eq? a (car (cons a b))
(eq? b (cdr (cons a b))

So is it possible to create a pair of 2 lists??? Well i’m thinking of
a solution is that converting a list to symbol but actually those are
2 completely different thing -> impossible as i understand.

It’s quite possible; if you have two lists, e.g., list1 and list2, you can create a pair whose car is list1 and whose cdr is list2 just by calling (cons list1 list2). Now, I think the issue that you’re running up against is that you’re expecting to see (<value-of-list1> . <value-of-list2>) as the output, and you’re seeing some different. To explain why this is, we need to understand how lists are represented in Lisps, and how pairs are printed.

A list in Scheme is either the empty list () (also known as nil in some Lisps), or a cons cell whose car (also known as first) is an element of the list and whose cdr (also known as rest) is either the rest of the list (i.e., another list), or an atom that terminates the list. The conventional terminator is the empty list (); lists terminated by () are said to be “proper lists”. Lists terminated by any other atom are called “improper lists”. The list (1 2 3 4 5) contains the elements 1, 2, 3, 4, and 5, and is terminated by (). You could construct it by

(cons 1 (cons 2 (cons 3 (cons 4 (cons 5 ())))))

Now, when the system prints a cons cell, the general case is to print it by

(car . cdr)

For instance, the result of (cons 1 2) is printed as

(1 . 2)

Since lists are built of cons cells, you can use this notation for lists too:

'(1 2 3 4 5) ==
'(1 . (2 . (3 . (4 . (5 . ())))))

That’s rather clunky, though, so most lisps (all that I know of) have a special case for printing cons cells: if the cdr is a list (either another cons cell, or ()), then don’t print the ., and don’t print the surrounding parenthesis of the cdr (which it would otherwise have, since it’s a list).

Now we can explain why the result of (cons list1 list2) doesn’t look like (<value-of-list1> . <value-of-list2>). If you call cons with two lists, you do get back a pair with the expected car and cdr, but it’s not printed with the . notation. E.g.,

(cons '(1 2 3) '(a b c))
;=> ((1 2 3) . (a b c))   ; which is typically *printed* as
;=> ((1 2 3) a b c)

But again, the printed representation doesn’t really matter though, as long as the following equations hold:

(eq? a (car (cons a b))
(eq? b (cdr (cons a b))

Sure enough:

(car (cons '(1 2 3) '(a b c)))
;=> (1 2 3)

(cdr (cons '(1 2 3) '(a b c)))
;=> (a b c)

In the specific example you’re asking about, consider what happens when you call

(cons '(prov:label "entity e0") '(prov:location "London"))

The result is, in fact,

((prov:label "entity e0") . (prov:location "London"))

but, because of the printing rules, this is printed as

((prov:label "entity e0") prov:location "London")

Nonetheless, you can still get the two attributes out by using car and cdr:

(car '((prov:label "entity e0") prov:location "London"))
;=> (prov:label "entity e0")

(cdr '((prov:label "entity e0") prov:location "London"))
;=> (prov:location "London")

and that’s all you really need to be able to do later.

Leave a Comment