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.
[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.
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.
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².
Related
I am new to Elixir language and I am having some issues while writing a piece of code.
What I am given is a 2D array like
list1 = [
[1 ,2,3,4,"nil"],
[6,7,8,9,10,],
[11,"nil",13,"nil",15],
[16,17,"nil",19,20] ]
Now, what I've to do is to get all the elements that have values between 10 and 20, so what I'm doing is:
final_list = []
Enum.each(list1, fn row ->
Enum.each(row, &(if (&1 >= 10 and &1 <= 99) do final_list = final_list ++ &1 end))
end
)
Doing this, I'm expecting that I'll get my list of numbers in final_list but I'm getting blank final list with a warning like:
warning: variable "final_list" is unused (there is a variable with the same name in the context, use the pin operator (^) to match on it or prefix this variable with underscore if it is not meant to be used)
iex:5
:ok
and upon printing final_list, it is not updated.
When I try to check whether my code is working properly or not, using IO.puts as:
iex(5)> Enum.each(list1, fn row -> ...(5)> Enum.each(row, &(if (&1 >= 10 and &1 <= 99) do IO.puts(final_list ++ &1) end))
...(5)> end
...(5)> )
The Output is:
10
11
13
15
16
17
19
20
:ok
What could I possibly be doing wrong here? Shouldn't it add the elements to the final_list?
If this is wrong ( probably it is), what should be the possible solution to this?
Any kind of help will be appreciated.
As mentioned in Adam's comments, this is a FAQ and the important thing is the message "warning: variable "final_list" is unused (there is a variable with the same name in the context, use the pin operator (^) to match on it or prefix this variable with underscore if it is not meant to be used)" This message actually indicates a very serious problem.
It tells you that the assignment "final_list = final_list ++ &1" is useless since it just creates a local variable, hiding the external one. Elixir variables are not mutable so you need to reorganize seriously your code.
The simplest way is
final_list =
for sublist <- list1,
n <- sublist,
is_number(n),
n in 10..20,
do: n
Note that every time you write final_list = ..., you actually declare a new variable with the same name, so the final_list you declared inside your anonymous function is not the final_list outside the anonymous function.
I am fairly new to functional programming and I do not understand my error here. I am trying to make a function that takes an integer list and returns both the sum of the even elements and the sum of the odd elements. The error I am getting is in line 1, and it states: "Error: right-hand-side of clause doesn't agree with function result type [overload conflict] ...". I don't understand the error, and I would appreciate any help in understanding my error.
fun add(nil) = 0
| add([x]) = x
| add(x :: xs) =
let
val evenList = xs;
val oddList = x :: xs
in
(hd evenList + add(tl(tl(evenList))), hd oddList + add(tl(tl(oddList))))
end;
The reason for the type error is that the function should return a pair, but your base cases don't.
I suspect you got to that code by thinking about skipping every other element, dividing the list by skipping.
There's a different way to approach this.
Consider the list [a,b,c,d].
Counting from 1, the elements are numbered
1 2 3 4
a b c d
Now consider the positions in the tail of the list.
They are
1 2 3
b c d
That is, odd positions in the tail are even positions in the entire list, and even positions in the tail are odd in the entire list.
This means that if we recursively compute "odds and evens" in the tail, we will get the sums from the tail, where its "odds" is our "evens", and if we add our head to the tail's "evens", we will get the "odds" we want.
All we need now is a good base case – and the sums of an empty list must be (0, 0).
Something like this:
fun add [] = (0,0)
| add (x::xs) = case add xs of
(odds, evens) => (x + evens, odds)
or, you can deconstruct the recursive result with a let-binding instead of case:
fun add [] = (0,0)
| add (x::xs) = let val (odds, evens) = add xs
in
(x + evens, odds)
end
I'm new to Julia and learning use of Map, reduce, filter.
It is becoming very hard for me to comprehend how it can replace for and while loops.
For ex for below code, I would like to replace for loop
function addMultiplesOf3And5(N::Int)
sumOfMultiples = 0
if(N == 3)
return sumOfMultiples + N
end
for i = 3:N-1
if(i % 3 == 0 && i % 5 == 0)
continue
elseif(i % 3 == 0)
sumOfMultiples += i
elseif(i % 5 == 0)
sumOfMultiples += i
end
end
return sumOfMultiples
end
I would really appreciate the help.
Update :
This is what I did after going through tutorials
function addMultiplesOf3And5(N::Int)
array = range(1,N-1)
return reduce(+, map(x -> multiples_of_3_Or_5(x), array))
end
function multiples_of_3_Or_5(n)
if(n % 3 == 0 && n % 5 == 0)
return 0
elseif(n % 3 == 0)
return n
elseif(n % 5 == 0)
return n
else
return 0
end
end
Final:
function addMultiplesOf3And5(N::Int)
array = range(1,N-1)
return reduce(+, filter(x -> ((x%3==0)$(x%5==0)), array))
end
To understand how you can replace your 'for loop + if block' code with 'map / reduce / filter' you need to know exactly how they work and why they might be chosen instead.
1. The map function
map is a function that takes a function variable and a list as arguments, and returns a new list, where each element is the result of applying the function to each element of the old list. So for example if your variable f refers to a function f(x) = x + 5 you defined earlier, and you have a list L=[1,2,3,4,5], then map(f, L) will return [f(L[1]), f(L[2]), f(L[3]), f(L[4]), f(L[5])]
So if you have code like:
f(x) = x + 5;
L = [1,2,3,4,5];
A = zeros(5);
for i in L
A[i] = f(i);
end
You could rewrite this as a mapping operation like so:
A = map(x -> x + 5, [1,2,3,4,5]);
2. The reduce function
reduce takes a binary function variable (i.e. a function that takes two arguments) and a list as arguments. What it does is probably best explained by an example. Calling reduce with the + operator, and list [1,2,3,4,5] will do the following:
Step 1: [1, 2, 3, 4, 5] % : 5 elements
Step 2: [1+2, 3, 4, 5] % [3,3,4,5] : 4 elements
Step 3: [3+3, 4, 5] % [6, 4, 5] : 3 elements
Step 4: [6+4, 5] % [10, 5] : 2 elements
Step 5: [10+5] % [15] : 1 elements
result: 15
i.e. we have reduced the list to a single result by successively applying the binary function to the first pair of elements, consuming the list little by little.
So if you have code like:
f(x,y) = x + y
L = [1,2,3,4,5];
A = L[1];
for i in 2:length(L)
A = f(A, L[i])
end
you could rewrite this as a reduce operation like so:
A = reduce(x,y -> x+y, [1,2,3,4,5])
3. The filter function
filter takes a predicate function (e.g. iseven, isnull, ==, or anything that takes an argument and performs a test on it, resulting in true or false) and a list, tests each element of the list with the function and returns a new list that only contains the elements that pass that test. e.g.
filter(iseven, [1,2,3,4,5]) # returns [2,4]
The answer to your problem
If I understand correctly, addMultiplesOf3And5 takes a number N (e.g. 20), and does the following:
filter out all the elements that can be divided by either 3 or 5 from the list [1,2,3,...,20]
successively add all elements of the resulting list together using a reduce function.
You should be able to use the above to figure out the exact code :)
Not sure what the function in the question is supposed to calculate, but:
addMult3or5(N) = N==3 ? 3 : sum(filter(x->((x%3==0)$(x%5==0)),3:N-1))
calculates the same thing.
sum is a a reduce-like function for the + operation.
Hope this helps clarify.
Also, $ is the exclusive-or operation in Julia.
I have finally found an excellent entry point into functional programming with elm, and boy, do I like it, yet I still lack some probably fundamental elegance concerning a few concepts.
I often find myself writing code similar to the one below, which seems to be doing what it should, but if someone more experienced could suggest a more compact and direct approach, I am sure that could give some valuable insights into this so(u)rcery.
What I imagine this could boil down to, is something like the following
(<-> is a vector subtraction operator):
edgeDirections : List Vector -> List Vector
edgeDirections corners = List.map2 (\p v -> p <-> v) corners (shiftr 1 corners)
but I don't really have a satisfying approach to a method that would do a shiftr.
But the rules of stackoverflow demand it, here is what I tried. I wrote an ugly example of a possible usage for shiftr (I absolutely dislike the Debug.crash and I am not happy about the Maybe):
Given a list of vectors (the corner points of a polygon), calculate the directional vectors by calculating the difference of each corner-vector to its previous one, starting with the diff between the first and the last entry in the list.
[v1,v2,v3] -> [v1-v3,v2-v1,v3-v2]
Here goes:
edgeDir : Vector -> ( Maybe Vector, List Vector ) -> ( Maybe Vector, List Vector )
edgeDir p ( v, list ) =
case v of
Nothing ->
Debug.crash ("nono")
Just vector ->
( Just p, list ++ [ p <-> vector ] )
edgeDirections : List Vector -> List Vector
edgeDirections corners =
let
last =
List.head <| List.reverse corners
in
snd <| List.foldl edgeDir ( last, [] ) corners
main =
show <| edgeDirections [ Vector -1 0, Vector 0 1, Vector 1 0 ]
I appreciate any insight into how this result could be achieved in a more direct manner, maybe using existing language constructs I am not aware of yet, or any pointers on how to lessen the pain with Maybe. The latter may Just not be possible, but I am certain that the former will a) blow me away and b) make me scratch my head a couple times :)
Thank you, and many thanks for this felicitous language!
If Elm had built-in init and last functions, this could be cleaner.
You can get away from all those Maybes by doing some pattern matching. Here's my attempt using just pattern matching and an accumulator.
import List exposing (map2, append, reverse)
shiftr list =
let shiftr' acc rest =
case rest of
[] -> []
[x] -> x :: reverse acc
(x::xs) -> shiftr' (x::acc) xs
in shiftr' [] list
edgeDirections vectors =
map2 (<->) vectors <| shiftr vectors
Notice also the shortened writing of the mapping function of (<->), which is equivalent to (\p v -> p <-> v).
Suppose Elm did have an init and last function - let's just define those quickly here:
init list =
case list of
[] -> Nothing
[_] -> Just []
(x::xs) -> Maybe.map ((::) x) <| init xs
last list =
case list of
[] -> Nothing
[x] -> Just x
(_::xs) -> last xs
Then your shiftr function could be shortened to something like:
shiftr list =
case (init list, last list) of
(Just i, Just l) -> l :: i
_ -> list
Just after I "hung up", I came up with this, but I am sure this can still be greatly improved upon, if it's even correct (and it only works for n=1)
shiftr : List a -> List a
shiftr list =
let
rev =
List.reverse list
in
case List.head rev of
Nothing ->
list
Just t ->
[ t ] ++ (List.reverse <| List.drop 1 rev)
main =
show (shiftr [ 1, 2, 3, 4 ] |> shiftr)
So, In a string containing multiple 1's,
Now, it is possible that, the number
'1'
appears at several positions, let's say, at multiple positions. What I want is
(3)
This is not a complete answer, but some ideas (partly based on comments):
z <- "1101101101"
zz <- as.numeric(strsplit(z,"")[[1]])
Compute autocorrelation function and draw plot: in this case I'm getting the periodicity=3 pretty crudely as the first point at which there is an increase followed by a decrease ...
a1 <- acf(zz)
first.peak <- which(diff(sign(diff(a1$acf[,,1])))==-2)[1]
Now we know the periodicity is 3; create runs of 3 with embed() and analyze their similarities:
ee <- embed(zz,first.peak)
pp <- apply(ee,1,paste,collapse="")
mm <- outer(pp,pp,"==")
aa <- apply(mm[!duplicated(mm),],1,which)
sapply(aa,length) ## 3 3 2 ## number of repeats
sapply(aa,function(x) unique(diff(x))) ## 3 3 3
The following code does exactly what you ask for. Try it with str_groups('1101101101'). It returns a list of 3-vectors. Note that the first triple is (1, 3, 4) because the character at the 10th position is also a 1.
Final version, optimized and without errors
str_groups <- function (s) {
digits <- as.numeric(strsplit(s, '')[[1]])
index1 <- which(digits == 1)
len <- length(digits)
back <- length(index1)
if (back == 0) return(list())
maxpitch <- (len - 1) %/% 2
patterns <- matrix(0, len, maxpitch)
result <- list()
for (pitch in 1:maxpitch) {
divisors <- which(pitch %% 1:(pitch %/% 2) == 0)
while (index1[back] > len - 2 * pitch) {
back <- back - 1
if (back == 0) return(result)
}
for (startpos in index1[1:back]) {
if (patterns[startpos, pitch] != 0) next
pos <- seq(startpos, len, pitch)
if (digits[pos[2]] != 1 || digits[pos[3]] != 1) next
repeats <- length(pos)
if (repeats > 3) for (i in 4:repeats) {
if (digits[pos[i]] != 1) {
repeats <- i - 1
break
}
}
continue <- F
for (subpitch in divisors) {
sublen <- patterns[startpos, subpitch]
if (sublen > pitch / subpitch * (repeats - 1)) {
continue <- T
break
}
}
if (continue) next
for (i in 1:repeats) patterns[pos[i], pitch] <- repeats - i + 1
result <- append(result, list(c(startpos, pitch, repeats)))
}
}
return(result)
}
Note: this algorithm has roughly quadratic runtime complexity, so if you make your strings twice as long, it will take four times as much time to find all patterns on average.
Pseudocode version
To aid understanding of the code. For particulars of R functions such as which, consult the R online documentation, for example by running ?which on the R command line.
PROCEDURE str_groups WITH INPUT $s (a string of the form /(0|1)*/):
digits := array containing the digits in $s
index1 := positions of the digits in $s that are equal to 1
len := pointer to last item in $digits
back := pointer to last item in $index1
IF there are no items in $index1, EXIT WITH empty list
maxpitch := the greatest possible interval between 1-digits, given $len
patterns := array with $len rows and $maxpitch columns, initially all zero
result := array of triplets, initially empty
FOR EACH possible $pitch FROM 1 TO $maxpitch:
divisors := array of divisors of $pitch (including 1, excluding $pitch)
UPDATE $back TO the last position at which a pattern could start;
IF no such position remains, EXIT WITH result
FOR EACH possible $startpos IN $index1 up to $back:
IF $startpos is marked as part of a pattern, SKIP TO NEXT $startpos
pos := possible positions of pattern members given $startpos, $pitch
IF either the 2nd or 3rd $pos is not 1, SKIP TO NEXT $startpos
repeats := the number of positions in $pos
IF there are more than 3 positions in $pos THEN
count how long the pattern continues
UPDATE $repeats TO the length of the pattern
END IF (more than 3 positions)
FOR EACH possible $subpitch IN $divisors:
check $patterns for pattern with interval $subpitch at $startpos
IF such a pattern is found AND it envelopes the current pattern,
SKIP TO NEXT $startpos
(using helper variable $continue to cross two loop levels)
END IF (pattern found)
END FOR (subpitch)
FOR EACH consecutive position IN the pattern:
UPDATE $patterns at row of position and column of $pitch TO ...
... the remaining length of the pattern at that position
END FOR (position)
APPEND the triplet ($startpos, $pitch, $repeats) TO $result
END FOR (startpos)
END FOR (pitch)
EXIT WITH $result
END PROCEDURE (str_groups)
Perhaps the following route will help:
Convert string to a vector of integers characters
v <- as.integer(strsplit(s, "")[[1]])
Repeatedly convert this vector to matrices of varying number of rows...
m <- matrix(v, nrow=...)
...and use rle to find relevant patterns in the rows of the matrix m:
rle(m[1, ]); rle(m[2, ]); ...