views:

197

answers:

3

Hi:

I'm having trouble understanding this line.

[Pid2 ! {delete, V1a}
    || {Pid1a, V1a} <- PV1a, Pid2 <- P2, Pid1a /= Pid2
  ],

Here is what I understand: anything before the double pipe "||" is done repeatedly, according what's after the double pipe. so messages with delete atom is repeated sent to Pid2. I know '/=' mean inequality. I don't understand what '<-' means, and ultimately what the whole line means.

+5  A: 

I don't know Erlang, but this looks just like list comprehensions from a bunch of languages I do know. Hopefully this guess will help you until somebody who knows Erlang can answer:

[Pid2 ! {delete, V1a} || {Pid1a, V1a} <- PV1a, Pid2 <- P2, Pid1a /= Pid2],

Translates to imperative-style pseudocode:

For each item in PV1a, unpacking item to {Pid1a, V1a}
    For each Pid2 in P2
        If Pid1a /= Pid2
            Pid2 ! {delete, V1a}

In other words, for each Pid in PV1a and P2, send the message delete V1a to Pid2 as long as Pid1 and Pid2 are not the same Pid.

Nathan Sanders
could you explain the unpacking part? what do you mean by unpacking?
Quincy
Here we use pattern matching to first check that an element of the list PV1a is a tuple of two elements and to pull apart the tuple into its elements, Pid1a and V1a. Pattern matching is fundamental to erlang and ubiquitous in erlang code.
rvirding
+12  A: 

[something(X) || X <- L], is a list comprehension. L is a list of elements, and this expression creates a list of new elements, forming each element by invoking something() on it.

[something(X,Y) || X <-L, Y<-M] is similar, but an element is created for the Cartesian product of each element in X and Y.

[something(X) || X <-L, Expr] is a filter expression. Same as the first one, but it is executed only for elements of L, where Expr is true for the given X.

[something(X) || {X,..} <-L, Expr] is another kind of filter. In the list comprehension only those elements are taken that can be matched by the element.

One more thing to know is that this can not only be used for generating another list, but also for executing a command for each element. If the result of the list comprehension is not matched, the compiler will know not to generate a list at all. This behavior can be used to mimic foreach from other languages.

Some examples:

1> [ X*2 || X <- [1,2,3] ].
[2,4,6]
2> [ X*Y || X <- [1,2], Y <- [3,4,5] ].
[3,4,5,6,8,10]
3> [ X*3 || X <- [1,2,3,4], X rem 2 == 0 ].
[6,12]
4> [ X || {a,X} <- [{a,1},{a,2},{b,3},{c,4}] ].
[1,2]

So your code generates the Cartesian product of all {Pid1a, V1a} elements from PV1a and Pid2 elements from P2, except for those elements where Pid1a equals Pid2, and for each of these pairs sends the {delete, V1a} message to Pid2.

Zed
+1  A: 

It is a list comprehension and the <- operator is used for generators.

Look at a more popular introduction example for LCs; to find triangles where the squares of the integer sides equals the square of the integer hypotenuse, but for a given range of integers Ns.

Ns = [1,2,3,4,5,6,7,8,9].
[{X,Y,C} || X <- Ns, Y <- Ns, C <- Ns, X*X + Y*Y == C*C].

This gives us the following list as output.

[{3,4,5},{4,3,5}]

Which seems correct:

3² + 4² = 5²
9 + 16 = 25
25 = 25

So the list comprehension can be read as give us every X,Y and C such that X is taken from Ns, Y is taken from Ns and C is taken from Ns, and X² + Y² equals C².

Christian