How is foldLeft evaluated in (0 /: (1 to 6))(_+_)? - scala

I was exploring the Scala foldLeft and its operator /:. And I came across an article here.
Here the /: is used to evaluate the sum of 1 to 6 as
(0 /: (1 to 6))(_+_)
The syntax of foldLeft that I am aware of is like Range./:(Initial Value){(z, i) => some anonymous function definition}
How is (0 /: (1 to 6))(_+_) evaluated and how does it work?

Operators ending in : are right associative. this means it's the same as explicitly using dot notation (1 to 6)./:(0)(_+_)
It is the same reason 1 :: 2 :: Nil doesn't have to be 1 :: (2 :: Nil)

Related

Difference between 1 :: 2 :: Nil vs. (1 :: (2 :: Nil))?

In the Scala tutorials I have been using, I have always seen lists constructed in this manner:
(1 :: (2 :: Nil))
Is there a difference between this and the non-parentheses version?
1 :: 2 :: Nil
They are the same. The parentheses can be added to illustrate the order of operation but they don't change anything. In fact they're rather pointless because no other order of operation is possible. In both cases the infix (i.e. dot-less) notation is de-sugared to the following.
Nil.::(2).::(1)
"How's that," you say? Remember that method names ending with a colon, :, reverse the class.method(argument) order when using infix notation.
Both are same when compiled by Scala compiler
(1 :: (2 :: Nil))
//res0: List[Int] = List(1, 2)
And
1 :: 2 :: Nil
//res1: List[Int] = List(1, 2)
The brackets used are just to show the grouping and order of prepending in a list as Nil being the last element.

How is foldLeft operator implemented in Scala?

Why does foldLeft syntax operator works, for example i would expect this code
(10 /: (1 to 5))(_ + _)
To give me an error "value /: is not a member of Int". How does it expands method /: on all types in type system?
Here is the definition of the "shortcut" operator:
def /:[B](z: B)(op: (B, A) => B): B = foldLeft(z)(op)
If operator ends with a colon, it is a right-associative. 1 :: Nil is another example, there is no method :: on Int
this all works:
(1 to 5)./:(10)(_ + _)
((1 to 5) foldLeft 10)(_ + _) (almost the same as your example,
but here it's more obvious that foldLeft is actually a method on the
range object)
(1 to 5).foldLeft(10)(_ + _)
Your question is not entirely clear (there's no n mentioned in your expression), but: Operators that end with a colon are interpreted as methods on the right-hand argument, not the left. Your expression is equivalent to
(1 to 5)./:(10)(_ + _)
in which /: is more clearly seen to be a method of the Range object on the left.

Accessing the Accumulator & Element in `foldl`

In Scala's foldLeft, I know how to access the accumulator and element values in Scala, but not Haskell.
I could use foldLeft to find out, between 1 and 100, how many numbers have a remainder of 1 when divided by 3:
scala> List.range(1, 101).foldLeft(0){ (acc, elem) =>
| if (elem % 3 == 1) acc + 1
| else acc
| }
res2: Int = 33
How can I do the same in Haskell?
There's essentially a 1-to-1 correspondence:
mySum :: [Int] -> Int
mySum xs = foldl (\acc elem ->
if elem `mod` 3 == 1
then acc + 1
else acc
) 0 xs
Other than syntax and order of arguments, there's no real difference.
For future readers, it is recommended to avoid using foldl in practice. Due to laziness in foldl's implementation, space leaks can occur for large lists. Instead, there is a strict version foldl' which can be used as a drop-in replacement or the right fold foldr which has a bit format:
mySum xs = foldr (\elem acc -> -- order of arguments swapped
if elem `mod` 3 == 1
then acc + 1
else acc
) 0 xs
This is a direct translation of your Scala code to Haskell:
foldl (\acc x -> if x `mod` 3 == 1 then acc + 1 else acc) 0 [1..100]
In Haskell, because of laziness of it, using foldl usually is not a good idea, a better choose is foldl' or foldr, here is the foldr version:
foldr (\x acc -> if x `mod` 3 == 1 then acc + 1 else acc) 0 [1..100]
It's rather similar:
foldl (\acc x -> if (x `mod` 3 == 1) then acc + 1 else acc) 0 [1..100]
The first argument to foldl is the lambda, the second is the accumulator 0 and the third is the range of values.
Refer to this question to understand the differences between foldl, foldl' and foldr.

How to understand function reduceLeft?

Why can (1 :: xs) be inserted?
One is cons'd onto beginning of list xs.
So List(3,2,1) becomes List(1,3,2,1) but what is significance of (1 :: xs)?
I'm having trouble understanding how this works :
def product(xs : List[Int]) = (1 :: xs) reduceLeft((x , y) => x * y)
In method signature a prefix operand (in this case (1 :: xs)) is not described? :
def reduceLeft[B >: A](f: (B, A) => B): B =
(1 :: xs) is not a prefix operand.
You are actually adding 1 before your list xs.
So product(List(3,2,1)) becomes List(1,3,2,1) reduceLeft((x,y) => x * y).
The reduceLeft function will take the 2 elements on the left and replace by the result of your function (x,y) => x * y.
In your case
List(1,3,2,1) => takes (1,3) and replaces by 1* 3 = 3 new List: List(3,2,1)
List(3,2,1) => takes (3,2) and replaces by 3 *2 = 6 new List: (6,1)
Finally takes (6,1) and get the final result 6.
As multiplying by one has no effect in the product, we add the number 1 before the List to avoid an error if the List is Empty.
Remove that and try product(List()) and you will see. If the List had at least on element (1::xs) will have no effect in your function
I believe you understand cons just fine. (1 :: xs) is simply another way to express List(1,3,2,1), on which you then invoke reduceLeft.
As for a better understanding of reduceLeft, I recently blogged this exact topic.
That's not a prefix operand--it's a method invocation on a List instance. The method reduceLeft is being called on the List (1 :: xs).
(1 :: xs) reduceLeft((x , y) => x * y)
can also be written as
(1 :: xs).reduceLeft((x , y) => x * y)
Or, even more explicitly:
val myList = (1 :: xs)
myList.reduceLeft((x , y) => x * y)

Scala: Is operator foldl infix?

Looking at code with foldl it is hard to understand its syntax, for example:
def lstToMap(lst:List[(String,Int)], map: Map[String, Int] ):Map[String, Int] = {
(map /: lst) (addToMap)
}
Is /: infix operator? What does (map /: lst) mean, partial application? Why I can not call like this:
`/: map lst addToMap`
Method names that end in a : character can be used on the left hand side of the instance they're bound to (ie, they associate to the right). In this case, /: is a method on List. As per the Scaladoc:
Note: /: is alternate syntax for foldLeft; z /: xs is the same as xs foldLeft z.
An alternative to what you wrote would be:
lst./:(map)(addToMap)
Edit: and another alternative with foldLeft:
lst.foldLeft(map)(addToMap)
Yes, /: can be used as an infix operator. However, the fold operation takes three arguments:
The sequence to fold across
The initial value for the reduction
The function used for folding
Using infix you can only specify two of these three arguments: the sequence (which is the receiver) and the initial value. The fact that (map /: lst) is a partial application reflects the fact that you're still missing an argument. Here's an example of a product of a sequence of numbers, starting with an initial value of 1:
(1 /: xs)(_*_)
Since Scala supports curly braces for function literals, you can also use that to make the function argument look more like a function body:
(1 /: xs) { (x, y) =>
x * y
}