简体   繁体   中英

Misunderstanding of the cons operator

This is a general question in relation to cons ( | ) operator in erlang. I'm going over a sample exam and there exists this question:

f2([A1, A2 | A1]) ->
{A2, A1};
f2([A, true | B]) ->
{A, B};
f2([A1, A2 | _]) ->
{A1, A2};
f2([_ | B]) ->
[B];
f2([A]) ->
{A};
f2(_) ->
nothing_matched.

I am confused as to why the following input: ([[a], [b] , a]) results in the output: {[b], [a]}

Why is this? From my understanding if the split from the second element in the list (which is the empty list, []) is the same as the first element, then the output will be: A2, A1. If the 3rd element a becomes a list, [a], then the output is then: {[a], [b]}. Why?

This is because in proper list the right side of [... | ...] [... | ...] operator is expected to be a list. Elements on the left are attached or extracted values of head elements which can be other lists too, it doesn't matter. Last element of left side points to right side. It means that in this case first element matches the tail list

[A1, A2 | A1] = [[a], [b], a] = [[a], [b] | [a]] = [[a], [b]] ++ [a].

You can't write [a,b,c | d,e,f,g] [a,b,c | d,e,f,g] , you can have only one tail. But [a,b,c | [d,e,f,g]] [a,b,c | [d,e,f,g]] will work and is equal to [a,b,c,d,e,f,g] . It means that you construct list element with value a which points to list element of value b which points to list element of value c which points to the right side (no matter what). Its equivalent (using only a | operator without commas) is:

[a | [b | [c | [d | [e | [f | [g]]]]]]] [a | [b | [c | [d | [e | [f | [g]]]]]]] .

To understand it you should think of it rather this way than with commas. Binding example: [El1, El2 | Tail] = [a,b,c,d], [El1 | [El2 | Tail]] = [a,b,c,d]. [El1, El2 | Tail] = [a,b,c,d], [El1 | [El2 | Tail]] = [a,b,c,d]. In both cases El1 = a, El2 = b and Tail = [c,d] = [c | [d]] = [c | [d | []]] Tail = [c,d] = [c | [d]] = [c | [d | []]] Tail = [c,d] = [c | [d]] = [c | [d | []]] .

As you see [[a],[b], a] means that list element of value [a] (which is list element of value a which points to an empty list [] ) points to an list element of value [b] which points to an list element of value a which points to an empty list [] .

Every proper list last element is pointing at empty list [] so it's true that [a,b,c] == [a,b,c | []]. [a,b,c] == [a,b,c | []]. But there are also improper lists and you can construct them by using non list as a tail like [a,b,c | d] [a,b,c | d] but this is useful only in specific situations and most of list operations can't by applied to them. One example of usage is lazy evaluation where tail is a function.

I've just found similar question to yours, it's here . If it's still not clear, you may find wiki page about singly linked list useful.

([[a], [b] , a]) will match the first clause f2([A1, A2 | A1]) -> {A2, A1}; .

so [A1, A2 | A1] = [[a], [b] , a] [A1, A2 | A1] = [[a], [b] , a] , you can get A1 = [a], A2 = [b] , the important is the second A1 , A1 = [a] .

The operator | is used for a recursive definition of a list: [A|B] means that you add the element A to an existing list B. A is the first element of the resulting list, called the head, B is the rest of the list called tail. B can be also split into a head and a tail, and the process can continue until the tail is equal to the empty list [].

Your example can be written in different ways:

L = [[a], [b] , a]. % element list representation
L = [[a]|[[b]|[a|[]]]]. % cons list representation
L = [[a],[b]|[a]]. % mixed representation

In the last one you can recognize the pattern [A1, A2 | A1] [A1, A2 | A1] of the first clause of the f2/1 function, so you get the result {A2,A1} = {[b],[a]} .

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