Left-hand side and right-hand side in multiple assignment - ruby

I'm having trouble understanding these two sections in ruby-doc:
Implicit Array Assignment
Multiple Assignment
When it says left-hand side, the splat operator is on the right side, and when it says right-hand side, the operator is on the left side. For example:
The * can appear anywhere on the right-hand side:
*a, b = 1, 2, 3
p a: a, b: b # prints {:a=>[1, 2], :b=>3}
Can anyone explain me what the meaning of left-hand side and right-hand side is in these sections? To me, examples seem contradictory.

I think this is a mistake in this v2.0.0 reference manual. Your understanding is correct.
Both have been fixed in the v2.2.0 manual (Implicit Array Assignment and Multiple Assignment).

I think it is supposed to mean what you have in mind. However, the document looks like it has mistakes. You can report this to the developers here as a documentation bug.

* will turn an argument list in to an array and visa versa:
def do_it(*args)
args
end
do_it(1, 'hello') # => [1, 'hello']
In the case of *a, b = 1, 2, 3 it is processed right to left, b is assigned 3 and the remaining arguments, 2 and 3 to a as an array, [2, 3].
In the case of a = 1, *[2,3], the array, [2, 3], is converted to arguments 2, 3. Therefore equivalent to a = 1, 2, 3.
Why a = 1, 2, 3 is valid and does not cause an error I do not know. I would guess, Ruby does an implicit splat when you supply multiple arguments to a single var assignment. So a = [1, 2, 3] is functionaly the same as a = 1, 2, 3.

Related

How is the splat operator understood when applied to a range expression?

I found that the expression [*1..4] returns the same as if I would do a (1..4).to_a, but I don't understand the syntax here. My understanding is that * is - being a unary operator in this case - to be the splat operator, and to the right of it, we have a Range. However, if just write the expression *1..4, this is a syntax error, and *(1..4) is a syntax error too. Why does the first [*1..4] work and how it is understood in detail?
The splat * converts the object to an list of values (usually an argument list) by calling its to_a method, so *1..4 is equivalent to:
1, 2, 3, 4
On its own, the above isn't valid. But wrapped within square brackets, [*1..4] becomes:
[1, 2, 3, 4]
Which is valid.
You could also write a = *1..4 which is equivalent to:
a = 1, 2, 3, 4
#=> [1, 2, 3, 4]
Here, the list of values becomes an array due to Ruby's implicit array assignment.

Why does the Ruby splat not work for array coercion in conditional assignment?

Although the splat (*) construct is commonly referred to as the splat operator, it is clear that it is a different beast, compared to other unary operators like the negation (!) operator.
The splat works fine on it's own (i.e. not wrapped in brackets) when used in assignment (=), but produces an error when used with conditional assignment (||=). Example:
a = *(1..3)
#=> [1, 2, 3]
b ||= *(1..3)
SyntaxError: (irb):65: syntax error, unexpected *
I am not looking for alternative ways of doing the same thing, but looking for someone with a better understanding of the Ruby internals to explain why this usage of the splat construct works in the first case but not in the second.
Here's my understanding of the practical goal of splat. This is for Ruby 2.2 MRI/KRI/YARV.
Ruby splat destructures an object into an array during assignment.
These examples all provide the same result, when a is falsey:
a = *(1..3)
a = * (1..3)
a =* (1..3)
a = *1..3
a = * 1..3
a = * a || (1..3)
a = * [1, 2, 3]
=> [1, 2, 3]
The splat does the destructuring during the assigment, as if you wrote this:
a = [1, 2, 3]
(Note: the splat calls #to_a. This means that when you splat an array, there's no change. This also means that you can define your own kinds of destructuring for any class of your own, if you wish.)
But these statements fail:
*(1..3)
* 1..3
* [1,2,3]
false || *(1..3)
x = x ? x : *(1..3)
=> SyntaxError
These statements fail because there's no assignment happening exactly when the splat occurs.
Your question is this special case:
b ||= *(1..3)
Ruby expands this to:
b = b || *(1..3)
This statement fails because there's no assignment happening exactly when the splat occurs.
If you need to solve this in your own code, you can use a temp var, such as:
b ||= (x=*(1..3))
Worth mentioning: there's an entirely different use of splat when it's on the left hand side of the expression. This splat is a low-priority greedy collector during parallel assignment.
Examples:
*a, b = [1, 2, 3] #=> a is [1, 2], b is 3
a, *b = [1, 2, 3] #=> a is 1, b is [2, 3]
So this does parse:
*a = (1..3) #=> a is (1..3)
It sets a to all the results on the right hand side, i.e. the range.
In the rare case that the splat can be understood as either a destructurer or a collector, then the destructurer has precendence.
This line:
x = * y = (1..3)
Evaluates to this:
x = *(y = (1..3))
Not this:
x = (*y = (1..3))
By splatting *(1..3) in your expression you get 1, 2, 3, and when it is assigned it behaves like mass assignment, but ruby seems not to support it for conditional assignment.
I.e. a=1,2,3 is just a syntax sugar of ruby. Just use an array explicitly:
a ||= [*1..3] #=> [1, 2, 3]
And actually you only use part of splat functionality here - it's autoconversion to array :) so you can simply do:
a ||= (1..3).to_a #=> [1, 2, 3]

Marking an unused block variable

When there is a block or local variable that is not to be used, sometimes people mark it with *, and sometimes with _.
{[1, 2] => 3, [4, 5] => 6}.each{|(x, *), *| p x}
{[1, 2] => 3, [4, 5] => 6}.each{|(x, _), _| p x}
{[1, 2, 3], [4, 5, 6]}.each{|*, x, *| p x}
{[1, 2, 3], [4, 5, 6]}.each{|_, x, _| p x}
def (x, *), *; p x; end
def (x, _), _; p x; end
def *, x, *; p x; end
def _, x, _; p x; end
What are the differences between them, and when should I use which? When there is need to mark multiple variables as unused as in the above examples, is either better?
A * means "all remaining parameters". An _ is just another variable name, although it is a bit special. So they are different, for example the following does not make sense:
[[1, 2, 3], [4, 5, 6]].each{|*, x, *| p x} # Syntax error
Indeed, how is Ruby supposed to know if the first star should get 0, 1 or 2 of the values (and the reverse)?
There are very few cases where you want to use a star to ignore parameters. An example would be if you only want to use the last of a variable number of parameters:
[[1], [2, 3], [4, 5, 6]].each{|*, last| p last} # => prints 1, 3 and 6
Ruby allows you to not give a name to the "rest" of the parameters, but you can use _:
[[1], [2, 3], [4, 5, 6]].each{|*_, last| p last} # => prints 1, 3 and 6
Typically, the number of parameters is known and your best choice is to use a _:
[[1, 2, 3], [4, 5, 6]].each{|_, mid, _| p mid} # prints 2 and 5
Note that you could leave the last paramater unnamed too (like you can when using a *), although it is less obvious:
[[1, 2, 3], [4, 5, 6]].each{|_, mid, | p mid} # prints 2 and 5
Now _ is the designated variable name to use when you don't want to use a value. It is a special variable name for two reasons:
Ruby won't complain if you don't use it (if warnings are on)
Ruby will allow you to repeat it in the argument list.
Example of point 1:
> ruby -w -e "def foo; x = 42; end; foo"
-e:1: warning: assigned but unused variable - x
> ruby -w -e "def foo; _ = 42; end; foo"
no warning
Example of point 2:
[[1, 2, 3], [4, 5, 6]].each{|unused, mid, unused| p mid}
# => SyntaxError: (irb):23: duplicated argument name
[[1, 2, 3], [4, 5, 6]].each{|_, mid, _| p mid}
# => prints 2 and 5
Finally, as #DigitalRoss notes, _ holds the last result in irb
Update: In Ruby 2.0, you can use any variable starting with _ to signify it is unused. This way the variable name can be more explicit about what is being ignored:
_scheme, _domain, port, _url = parse_some_url
# ... do something with port
I think it's mostly stylistic and programmer's choice. Using * makes more sense to me in Ruby because its purpose is to accumulate all parameters passed from that position onward. _ is a vestigial variable that rarely sees use in Ruby, and I've heard comments that it needs to go away. So, if I was to use either, I'd use *.
SOME companies might define it in their programming style document, if they have one, but I doubt it's worth most of their time because it is a throw-away variable. I've been developing professionally for over 20 years, and have never seen anything defining the naming of a throw-away.
Personally, I don't worry about this and I'd be more concerned with the use of single-letter variables. Instead of either, I would use unused or void or blackhole for this purpose.
IMO the practice makes code less readable, and less obvious.
Particularly in API methods taking blocks it may not be clear what the block actually expects. This deliberately removes information from the source, making maintenance and modification more difficult.
I'd rather the variables were named appropriately; in a short block it will be obvious it's not being used. In longer blocks, if the non-use is remarkable, a comment may elaborate on the reason.
What are the differences between them?
In the _ case a local variable _ is being created. It's just like using x but named differently.
In the * case the assignment of an expression to * creates [expression]. I'm not quite sure what it's useful for as it doesn't seem to do anything that just surrounding the expression with brackets does.
When should I use which?
In the second case you don't end up with an extra symbol being created but it looks like slightly more work for the interpreter. Also, it's obvious that you will never use that result, whereas with _ one would have to read the loop to know if it's used.
But I predict that the quality of your code will depend on other things than which trick you use to get rid of unused block parameters. The * does have a certain obscure cool-factor that I kind of like.
Note: when experimenting with this, be aware that in irb, _ holds the value of the last expression evaluated.

What does this mean in Ruby language?

Run the following code,
a = [1, 2, 3, 4, 5]
head, *tail = a
p head
p tail
You will get the result
1
[2, 3, 4, 5]
Who can help me to explain the statement head,*tail = a, Thanks!
head, *tail = a means to assign the first element of the array a to head, and assign the rest of the elements to tail.
*, sometimes called the "splat operator," does a number of things with arrays. When it's on the left side of an assignment operator (=), as in your example, it just means "take everything left over."
If you omitted the splat in that code, it would do this instead:
head, tail = [1, 2, 3, 4, 5]
p head # => 1
p tail # => 2
But when you add the splat to tail it means "Everything that didn't get assigned to the previous variables (head), assign to tail."
First, it is a parallel assignment. In ruby you can write
a,b = 1,2
and a will be 1 and b will be 2. You can also use
a,b = b,a
to swap values (without the typical temp-variable needed in other languages).
The star * is the pack/unpack operator. Writing
a,b = [1,2,3]
would assign 1 to a and 2 to b. By using the star, the values 2,3 are packed into an array and assigned to b:
a,*b = [1,2,3]
I don't know Ruby at all, but my guess is that the statement is splitting the list a into a head (first element) and the rest (another list), assigning the new values to the variables head and tail.
This mechanism is usually referred (at least in Erlang) as pattern matching.

Why is this Haskell incorrect?

I have a Haskell file which looks like this:
longest::[Integer]->[Integer]->[Integer]
max a b = if length a > length b then a else b
llfs::[Integer]->Integer
llfs li = length(foldl longest group(li))
llfs([1, 2, 3, 3, 4, 5, 1, 1, 1])
Which should print out the result of the function call at the end, however when I run the file I get this error:
parse error (possibly incorrect indentation)
I don't understand what I'm doing wrong. What should I do to fix it?
Edit
After putting the last line inside the main function, like this:
import List
longest::[Integer]->[Integer]->[Integer]
longest a b = if length a > length b then a else b
llfs::[Integer]->Integer
llfs li = length(foldl longest group(li))
main = print (llfs [1, 2, 3, 3, 4, 5, 1, 1, 1])
I now get the following error:
C:\Users\Martin\Desktop\Haskell\Q1.hs:7:31:
Couldn't match expected type `[Integer]'
against inferred type `[a] -> [[a]]'
In the second argument of `foldl', namely `group'
In the first argument of `length', namely
`(foldl longest group (li))'
In the expression: length (foldl longest group (li))
This one looks a little more difficult! How do I solve it?
Your code isn't correct.
This
longest::[Integer]->[Integer]->[Integer]
max a b = if length a > length b then a else b
should be
longest::[Integer]->[Integer]->[Integer]
longest a b = if length a > length b then a else b
And you need a main function
main = do print llfs([1, 2, 3, 3, 4, 5, 1, 1, 1])
Just for the sake of improving your code, if you have a function signature and give it a lower case letter(s) as its type (say the letter a), it becomes generic. For example
longest:: [a] -> [a] -> [a]
longest x y = if length x > length y then x else y
Means that rather than just working on lists of Integers, it works on lists of anything. Suddenly you have a very reusable function.
In the line
llfs li = length(foldl longest group(li))
the interpreter is treating group as the second argument to foldl. Writing group(li) is no different from writing group li.
Also, foldl needs an initial value. foldl1, on the other hand, uses the first list element for its initial value. Try:
llfs li = length (foldl1 longest (group li))
(Edited to remove the first, wrong answer.)
module Main where
import Data.List
longest::[Integer]->[Integer]->[Integer]
longest a b = if length a > length b then a else b
llfs::[Integer]->Int
llfs li = length $ foldl1 longest $ group li
main = do
putStrLn $ show $ llfs [1, 2, 3, 3, 4, 5, 1, 1, 1]
The problem was that the last line did not define a function, as others have stated. More things are wrong in your code. It appears this is what you want to do:
import Data.List
longest_group_size :: [Integer] -> Int
longest_group_size = maximum . map length . group
main :: IO ()
main = print $ longest_group_size [1, 2, 3, 3, 4, 5, 1, 1, 1]
Observe that:
You need to import Data.List in order to use group.
No need to use foldr in this case: by using map the length of each group is only calculated once.
This does mean, of course, that we call in the help of another function, maximum.
You cannot call a function at file scope like you would do in python or other scripting languages. Therefore the "call" to llfs in the last line is an error. Try printing the result in main:
main = print (llfs [1, 2, 3, 3, 4, 5, 1, 1, 1])
At the moment the "function call" looks like an incomplete function definition, where the right side is missing, which leads to the surprising error message:
llfs (...) = abc
The problem is this line:
llfs([1, 2, 3, 3, 4, 5, 1, 1, 1])
That's not a function declaration. I think you're trying to make a function call, in which case you need to put it inside a main declaration. You can also load the Haskell file into an interpreter (e.g., ghci) and execute the function call in the interpreter console.
This isn't the direct cause of either error, but I think it's a contributing factor to your misunderstanding. In Haskell, you would never write group(li). Parenthesizing a single argument is pointless — it's exactly equivalent to group li. If you're trying to pass the result of this function call to another function, you need to parenthesize the whole expression — (group li) — or use the $ operator like Caleb suggested.
Two small issues with the update. First, it looks like you're trying to pass the group result as an argument to foldl. The right way to say that is (group li) rather than group(li) The second is that foldl needs a base case. Caleb's suggestion to use foldl1 is one option that will probably work for you.

Resources