Hi I am new to scala and have a question.
When I specify the non abbreviated version of a funtion literal in a for loop, scala does nothing with it.
e.g.
val myList = List("one","two","tree","four","five")
//compiles but does not print anything
for (arg <- lst) (arg:String) => {println(arg)}
//does print one, two, tree, four,five on separated lines
lst.foreach((arg:String) => {println(arg)})
On the other hand the abbreviated version of the above function literal ( println(arg) ) in a for loop does seem to work as expected:
val myList = List("one","two","tree","four","five")
//does print one, two, tree, four,five on separated lines
for (arg <- lst) println(arg)
Is this a bug or did I misunderstand something?
thanks a lot
It's not a bug in Scala. When you specify the function, like this:
for (arg <- lst) (arg:String) => {println(arg)}
then Scala is indeed not doing anything with it, because you only specified the function - you didn't tell Scala to actually call the function. Your for loop basically means: "for each element in lst, declare this function".
You'll have to specify that you want the function to be called:
for (arg <- lst) ((arg:String) => {println(arg)})(arg)
This reads as: "for each element in lst, declare this function and call it with arg".
Note the difference with foreach:
lst.foreach((arg:String) => {println(arg)})
This means: "call foreach on lst, and pass it this function" - foreach is then going to call the function for each element in lst.
More of a side note, consider this
val a = for (arg <- lst) (arg:String) => {println(arg)}
a: Unit = ()
where a of type Unit does nothing, and
val b = for (arg <- lst) yield (arg:String) => {println(arg)}
b: List[String => Unit] = List(<function1>, <function1>, <function1>, <function1>, <function1>)
where we tell the for comprehension to deliver a collection of functions from String onto Unit (due to the println). Then we can apply each entry in lst to each corresponding function in b for instance like this,
(lst zip b).foreach { case (s, f) => f(s) }
one
two
tree
four
five
Note that f(s) is a shorthand for f.apply(s).
Related
I was learning Racket (University of Washington Programming Languages course on Coursera) and there is an interesting example to define a lazy stream of values in Racket:
(define ones
(lambda () (cons 1 ones)))
Basically this defines a function ones that returns a lambda that when called returns a tuple that the first element is 1 and the second element is the method itself.
I was trying to define this function in Scala but cannot get the typing right, there is some weird recursion going on:
def ones = () => (1, ones) // This complains that recursive function should have types
def ones: () => (Int, ???) = () => (1, ones) // What is the type here?
What's the correct type for this function?
Basically this defines a function ones that returns a lambda that when
called returns a tuple that the first element is 1 and the second
element is the method itself.
Here we go: (Do not recommend, scala 2.1 only)
import scala.language.existentials
type T = () => (Int, () => A) forSome { type A <: (Int, () => A) }
def ones: T = () => (1, ones)
val (i1, f1) = ones()
val (i2, f2) = f1()
val (i3, f3) = f2()
println(i1, i2, i3) // get (1, 1, 1)
Well (1, ones) is just a tuple, and a tuple has a fixed size so it can't be infinite, but you can just construct a LazyList just like in the racket example like this:
lazy val ones = 1 #:: ones
Or even simpler:
val ones = LazyList.continually(1)
I have created an immutable list and try to fold it to a map, where each element is mapped to a constant string "abc". I do it for practice.
While I do that, I am getting an error. I am not sure why the map (here, e1 which has mutable map type) is converted to Any.
val l = collection.immutable.List(1,2,3,4)
l.fold (collection.mutable.Map[Int,String]()) ( (e1,e2) => e1 += (e2,"abc") )
l.fold (collection.mutable.Map[Int,String]()) ( (e1,e2) => e1 += (e2,"abc") )
<console>:13: error: value += is not a member of Any
Expression does not convert to assignment because receiver is not assignable.
l.fold (collection.mutable.Map[Int,String]()) ( (e1,e2) => e1 += (e2,"abc") )
At least three different problem sources here:
Map[...] is not a supertype of Int, so you probably want foldLeft, not fold (the fold acts more like the "banana brackets", it expects the first argument to act like some kind of "zero", and the binary operation as some kind of "addition" - this does not apply to mutable maps and integers).
The binary operation must return something, both for fold and foldLeft. In this case, you probably want to return the modified map. This is why you need ; m (last expression is what gets returned from the closure).
The m += (k, v) is not what you think it is. It attempts to invoke a method += with two separate arguments. What you need is to invoke it with a single pair. Try m += ((k, v)) instead (yes, those problems with arity are annoying).
Putting it all together:
l.foldLeft(collection.mutable.Map[Int, String]()){ (m, e) => m += ((e, "abc")); m }
But since you are using a mutable map anyway:
val l = (1 to 4).toList
val m = collection.mutable.Map[Int, String]()
for (e <- l) m(e) = "abc"
This looks arguably clearer to me, to be honest. In a foldLeft, I wouldn't expect the map to be mutated.
Folding is all about combining a sequence of input elements into a single output element. The output and input elements should have the same types in Scala. Here is the definition of fold:
def fold[A1 >: A](z: A1)(op: (A1, A1) => A1): A1
In your case type A1 is Int, but output element (sum type) is mutable.Map. So if you want to build a Map throug iteration, then you can use foldLeft or any other alternatives where you can use different input and output types. Here is the definition of foldLeft:
def foldLeft[B](z: B)(op: (B, A) => B): B
Solution:
val l = collection.immutable.List(1, 2, 3, 4)
l.foldLeft(collection.immutable.Map.empty[Int, String]) { (e1, e2) =>
e1 + (e2 -> "abc")
}
Note: I'm not using a mutabe Map
This is a implementation of the Y-combinator in Scala:
scala> def Y[T](func: (T => T) => (T => T)): (T => T) = func(Y(func))(_:T)
Y: [T](func: (T => T) => (T => T))T => T
scala> def fact = Y {
| f: (Int => Int) =>
| n: Int =>
| if(n <= 0) 1
| else n * f(n - 1)}
fact: Int => Int
scala> println(fact(5))
120
Q1: How does the result 120 come out, step by step? Because the Y(func) is defined as func(Y(func)), the Y should become more and more,Where is the Y gone lost and how is the 120 come out in the peform process?
Q2: What is the difference between
def Y[T](func: (T => T) => (T => T)): (T => T) = func(Y(func))(_:T)
and
def Y[T](func: (T => T) => (T => T)): (T => T) = func(Y(func))
They are the same type in the scala REPL, but the second one can not print the result 120?
scala> def Y[T](func: (T => T) => (T => T)): (T => T) = func(Y(func))
Y: [T](func: (T => T) => (T => T))T => T
scala> def fact = Y {
| f: (Int => Int) =>
| n: Int =>
| if(n <= 0) 1
| else n * f(n - 1)}
fact: Int => Int
scala> println(fact(5))
java.lang.StackOverflowError
at .Y(<console>:11)
at .Y(<console>:11)
at .Y(<console>:11)
at .Y(<console>:11)
at .Y(<console>:11)
First of all, note that this is not a Y-combinator, since the lambda version of the function uses the free variable Y. It is the correct expression for Y though, just not a combinator.
So, let’s first put the part which computes the factorial into a separate function. We can call it comp:
def comp(f: Int => Int) =
(n: Int) => {
if (n <= 0) 1
else n * f(n - 1)
}
The factorial function can now be constructed like this:
def fact = Y(comp)
Q1:
Y is defined as func(Y(func)). We invoke fact(5) which is actually Y(comp)(5), and Y(comp) evaluates to comp(Y(comp)). This is the key point: we stop here because comp takes a function and it doesn’t evaluate it until needed. So, the runtime sees comp(Y(comp)) as comp(???) because the Y(comp) part is a function and will be evaluated only when (if) needed.
Do you know about call-by-value and call-by-name parameters in Scala? If you declare your parameter as someFunction(x: Int), it will be evaluated as soon as someFunction is invoked. But if you declare it as someFunction(x: => Int), then x will not be evaluated right away, but at the point where it is used. Second call is “call by name” and it is basically defining your x as a “function that takes nothing and returns an Int”. So if you pass in 5, you are actually passing in a function that returns 5. This way we achieve lazy evaluation of function parameters, because functions are evaluated at the point they are used.
So, parameter f in comp is a function, hence it is only evaluated when needed, which is in the else branch. That’s why the whole thing works - Y can create an infinite chain of func(func(func(func(…)))) but the chain is lazy. Each new link is computed only if needed.
So when you invoke fact(5), it will run through the body into the else branch and only at that point f will be evaluated. Not before. Since your Y passed in comp() as parameter f, we will dive into comp() again. In the recursive call of comp() we will be calculating the factorial of 4. We will then again go into the else branch of the comp function, thus effectively diving into another level of recursion (calculating factorial of 3). Note that in each function call your Y provided a comp as an argument to comp, but it is only evaluated in the else branch. Once we get to the level which calculates factorial of 0, the if branch will be triggered and we will stop diving further down.
Q2:
This
func(Y(func))(_:T)
is syntax sugar for this
x => func(Y(func))(x)
which means we wrapped the whole thing into a function. We didn’t lose anything by doing this, only gained.
What did we gain? Well, it’s the same trick as in the answer to a previous question; this way we achieve that func(Y(func)) will be evaluated only if needed since it’s wrapped in a function. This way we will avoid an infinite loop. Expanding a (single-paramter) function f into a function x => f(x) is called eta-expansion (you can read more about it here).
Here’s another simple example of eta-expansion: let’s say we have a method getSquare() which returns a simple square() function (that is, a function that calculates the square of a number). Instead of returning square(x) directly, we can return a function that takes x and returns square(x):
def square(x: Int) = x * x
val getSquare: Int => Int = square
val getSquare2: Int => Int = (x: Int) => square(x)
println(square(5)) // 25
println(getSquare(5)) // 25
println(getSquare2(5)) // 25
Hope this helps.
Complementing the accepted answer,
First of all, note that this is not a Y-combinator, since the lambda version of the function uses the free variable Y. It is the correct expression for Y though, just not a combinator.
A combinator isn't allowed to be explicitly recursive; it has to be a lambda expression with no free variables, which means that it can't refer to its own name in its definition. In the lambda calculus it is not possible to refer to the definition of a function in a function body. Recursion may only be achieved by passing in a function as a parameter.
Given this, I've copied the following implementation from rosetta code that uses some type trickery to implement Y combinator without explicit recursion. See here
def Y[A, B](f: (A => B) => (A => B)): A => B = {
case class W(wf: W => A => B) {
def get: A => B =
wf(this)
}
val g: W => A => B = w => a => f(w.get)(a)
g(W(g))
}
Hope this helps with the understanding.
I don't know the answer, but will try to guess. Since you have def Y[T](f: ...) = f(...) compiler can try to substitute Y(f) with simply f. This will create an infinite sequence of f(f(f(...))). Partially applying f you create a new object, and such substitution becomes impossible.
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
}
I have the following code:
val text = "some text goes here"
val (first, rest) = text.splitAt(4)
println(first + " *" + rest)
That works fine.
However, I want to have two cases, defining "first" and "rest" outside, like this:
val text = "some text goes here"
var (first, rest) = ("", "")
if (text.contains("z")) {
(first, rest) = text.splitAt(4)
} else {
(first, rest) = text.splitAt(7)
}
println(first + " *" + rest)
But that gives me an error:
scala> | <console>:2: error: ';' expected but '=' found.
(first, rest) = text.splitAt(4)
Why is it an error to do (first, rest) = text.splitAt(4) but not to do val (first, rest) = text.splitAt(4)? And what can I do?
Edit: Can't re-assign val, changed to var. Same error
The answer by Serj gives a better way of writing this, but for an answer to your question about why your second version doesn't work, you can go to the Scala specification, which makes a distinction between variable definitions and assignments.
From "4.2 Variable Declarations and Definitions":
Variable definitions can alternatively have a pattern (§8.1) as
left-hand side. A variable definition var p = e where p is a
pattern other than a simple name or a name followed by a colon and a
type is expanded in the same way (§4.1) as a value definition val p
= e, except that the free names in p are introduced as mutable variables, not values.
From "6.15 Assignments":
The interpretation of an assignment to a simple variable x = e depends
on the definition of x. If x denotes a mutable variable, then the
assignment changes the current value of x to be the result of
evaluating the expression e.
(first, rest) here is a pattern, not a simple variable, so it works in the variable definition but not in the assignment.
First of all val is immutable, so you can't reassign it. Second, if, like all control structures in Scala, can return a value. So, you can do it like this:
val text = "some text goes here"
val (first, rest) = if (text.contains("z")) text.splitAt(4) else text.splitAt(7)
println(first + " *" + rest)
SerJ de SuDDeN answer is absolutely correct but some more details why the code you mentioned works the way it works.
val (a, b) = (1, 2)
is called an extractor of a pattern-match-expression. The value on the right side is matched to the extractor of the left side. This can be done everywhere in Scala and can have different faces. For example a pattern match on a List can look something like
scala> val head :: tail = 1 :: 2 :: 3 :: Nil
head: Int = 1
tail: List[Int] = List(2, 3)
On the right side the ::-symbol is a method of class List which prepends elements to it. On the left side the ::-symbol is an extractor of class ::, a subclass of List.
Some other places can be for-comprehensions
scala> for ((a, b) <- (1 to 3) zip (4 to 6)) println(a+b)
5
7
9
or the equivalent notation with higher-order-methods
scala> (1 to 3) zip (4 to 6) foreach { case (a, b) => println(a+b) }
5
7
9