Scala lambda in function args - scala

I have some code block like this:
object EntryPoint extends App {
val arr = ArrayBuffer(1, 2, 3)
doFirst(arr)
def doFirst(a: ArrayBuffer[Int]) = {
doSecond(s"$a")
}
def doSecond(
x: => String = ""
) = {
x match {
case s: String => println(s"This is string: $s")
case _ => println(x.getClass.getName)
}
}
}
Output: This is string: ArrayBuffer(1, 2, 3)
Why x evaluated like a string if in debugger i see lambda with 3 arguments?
Is it because every call x is x.apply() ?

A by-name parameter like x: => String is conceptually the same as a function with signature () => String
The following are equivalent and as you noticed already both parameters end up with the same runtime representation when debugging.
def doWithByNameParam(x: => String): String =
x
def doWithFunction(x: () => String): String =
x.apply()
doWithByNameParam("string")
doWithFunction(() => "string")
You just avoid some boilerplate with doWithByNameParam
Later Edit:
Here's what javap will give just so you understand what happens under the hood
public static java.lang.String doWithByNameParam(scala.Function0<java.lang.String>);
public static java.lang.String doWithFunction(scala.Function0<java.lang.String>);

Related

High order functions in Scala

IM trying to understand the below high order functions in Scala but need some clarifications on the parameters of the functions.
Questions:-
What does the Int => String in the apply function mean?
v: Int indicates that the parameter v is of type Int.
What does the [A](x: A) mean in layout function?
object Demo {
def main(args: Array[String]) {
println( apply( layout, 10) )
}
def apply(f: Int => String, v: Int) = f(v)
def layout[A](x: A) = "[" + x.toString() + "]"
}
f: Int => String means that f is a function with one argument of type Int and with a return type String
def layout[A](x: A) means that parameter x is of type A, which can be of any type. Here are a couple of examples on how to invoke layout:
layout[String]("abc") //returns "[abc]"
layout[Int](123) //returns "[123]"
When main runs it invokes apply with the layout function and the argument 10. This will output "[10]"
The syntax of Int => String means passing a function that accepts Int and returns String.
Here is a useful example for passing function:
case class Person(name: String, lastName: String)
val person = Person("Johnny", "Cage")
def updateName(name: String) = {
updatePerson(_.copy(name = name))
}
def updateLastName(lastName: String) {
updatePerson(_.copy(lastName = lastName))
}
private def updatePerson(transformer: Person => Person): Unit = {
transformer(person)
}
Note how each update function passes the copy constructor.

Can function parameter be set before it's invoked?

Here I create a List of objects where each element is of type (String , () => Unit)
case class FunctionDesc(label: String, fun: () => Unit)
def f() = {
println("in f")
}
val functionList = List[FunctionDesc](FunctionDesc("a1", f), FunctionDesc("a2", f))
functionList.foreach(f => f.fun())
This works fine but if I want to modify the function List to contain a parameter then have to decide what the parameter value
should be when the function is being implemented :
case class FunctionDesc2(label: String, fun: (String) => Unit)
def f2(str: String) = {
println("in f2")
}
def f3(str: String) = {
println("in f3")
}
val functionList2 = List[FunctionDesc2](FunctionDesc2("a3", f2), FunctionDesc2("a4", f3))
functionList2.foreach(f => f.fun("param value"))
Can decide what the function parameter type should before it's invoked ?
So instead of
val functionList2 = List[FunctionDesc2](FunctionDesc2("a3", f2), FunctionDesc2("a4", f3))
use something like :
val functionList2 = List[FunctionDesc2](FunctionDesc2("a3", f2("f5")), FunctionDesc2("a4", f2("f6"))
You can achieve this by making f2 and f3 return a function. Here's a simplified version:
case class FunctionDesc2(label: String, fun: (String) => Unit)
// `f` closes over `str` and returns a function from `String` to `Unit`
def f(str: String) = (s: String) => println(s"$str: $s")
val functionList = List(FunctionDesc2("a", f("foo")), FunctionDesc2("b", f("bar")))
functionList.foreach(_.fun("value"))
// foo: value
// bar: value
You can use currying:
scala> case class FunctionDesc2(label: String, fun: () => Unit)
defined class FunctionDesc2
scala> def f2(str: String)(): Unit = {
| println("in f2")
| }
f2: (str: String)()Unit
scala> def f3(str: String)(): Unit = {
| println("in f3")
| }
f3: (str: String)()Unit
scala> val functionList2 = List[FunctionDesc2](FunctionDesc2("a3", f2("f5")), FunctionDesc2("a4", f3("f6")))
functionList2: List[FunctionDesc2] = List(FunctionDesc2(a3,<function0>), FunctionDesc2(a4,<function0>))
scala> functionList2.foreach(desc => desc.fun())
in f2
in f3

Why doesn't the Scala compiler accept this lambda as a parameter?

Suppose I have an interface for a Thing:
abstract class Thing[A](a_thing: A) {
def thingA = a_thing
}
and I implement that Thing as follows:
class SpecificThing(a: String) extends Thing[String](a)
Furthermore, suppose I have a function that takes a Thing and a lambda that does something to that Thing as parameters:
def doSomething[A](fn: Thing[A] => A, t: Thing[A]) : A = fn(t)
Now, let's use this stuff:
val st = new SpecificThing("hi")
val fn1: (Thing[String]) => String = (t: Thing[String]) => { t.thingA }
println(doSomething(fn1, st))
This prints hi. So far, so good. But I'm lazy, and I don't like typing so much, so I change my program to the following:
type MyThing = Thing[String]
val st = new SpecificThing("hi")
val fn2: (MyThing) => String = (t: MyThing) => { t.thingA }
println(doSomething(fn2, st))
and this also prints hi. Fabulous! The compiler can tell that a SpecificThing is both a Thing[String] and a MyThing. But what about this case?
val st = new SpecificThing("hi")
val fn3: (SpecificThing) => String = (t: SpecificThing) => { t.thingA }
println(doSomething(fn3, st))
Now I get:
Error:(14, 23) type mismatch;
found : SpecificThing => String
required: Thing[?] => ?
println(doSomething(fn3, st))
^
What's going on? What's a Thing[?]?
f3 isn't a Thing[String] => String, it's a SpecificThing => String. For an example of why they couldn't be compatible:
class SpecificThing2 extends Thing[String] {
def thingB = 2.0
}
val f4: SpecificThing2 => String = {
st: SpecificThing2 => f"%f${st.thingB / 3.0}"
}
val t = new Thing[String]("haha"){}
f4(t) // would be an error when f4 tried to access t.thingB
More formally, Function1 is contravariant in its first type parameter, Function1[-T, +R].
A Thing[?] is what it looks like; it's a Thing[X] for some unknown type X. The compiler is gamely trying to infer what the type A should be, but it can't make it work: it needs a Thing[A] => A for some (unknown-to-it) type A, and you're passing it a SpecificThing => String; that's the error.

Conditional application of one of two functions to one argument

I have two functions that take one argument, a String. I was to apply either one or the other based on some condition. This is what I attempted:
def foo(s: String) = { ... }
def bar(s: String) = { ... }
(if (condition) foo else bar)("baz")
But I get an error like this:
<console>:10: error: missing arguments for method foo;
follow this method with `_' if you want to treat it as a partially applied function
(if (true) foo else bar)("baz")
^
I tried writing foo_ but of course I got error: not found: value foo_. What's the correct way to express this idiom in Scala?
You need a space between the method name and the underscore. This works fine:
def foo(s: String) = s + "-FOO"
def bar(s: String) = s + "-BAR"
val condition = true
(if (condition) foo _ else bar _)("baz")
// res0: String = baz-FOO
The underscore after the method name tells Scala that you want to want to pass the method as a higher-level function. From what I understand, this is a way to disambiguate whether you want to pass a method as a function or pass the result of a method with no arguments. For example:
def f = 1
val x = Some(f)
What should the type of x be? Will it be Some[Int] or Some[()=>Int]? It should default to the former, but if you want the latter you can use the underscore notation:
val y = Some(f _)
You have to deal with all this underscore nonsense because Scala methods aren't functions. If you declare foo and bar as functions rather than methods then your original code works as-is:
val foo = (s: String) => s + "-FOO"
val bar = (s: String) => s + "-BAR"
val condition = false
(if (condition) foo else bar)("baz")
// res1: String = baz-BAR
There are several things I want to mention:
def foo(s: String) = { ... }
def bar(s: String) = { ... }
foo and bar are not functions, there are just normal method. Also, def f = 3 is also a method not function.
(if (condition) foo else bar)("baz") obviously, this statement need foo and bar to be a function because of ("baz") argument.
as #wendao mentioned to use _ to change method to function. I think the simplest solution is to define foo and bar as a function.
def foo: String => String = { value =>
"Hi " + value
}
def bar: String => String = { value =>
"farewell " + value
}
val x: Some[String => String] = Some(foo)
(if (true) foo else bar)("John") // Hi John
It doesn't know that what you actually want to return a function, you'd have to tell it that what you want is a by-name parameter:
def foo(x : String) = x //> foo: (x: String)String
def bar(x : String) = x //> bar: (x: String)String
val condition = true //> condition : Boolean = true
val result : String => String = if (condition) foo else bar
//> result : String => String = <function1>
result("something") //> res0: String = something
This is a little more absurd:
scala> var b = true
b: Boolean = true
scala> def f(s: String) = s"f+$s"
f: (s: String)String
scala> def g(s: String) = s"g+$s"
g: (s: String)String
scala> import Function._ ; import PartialFunction._
import Function._
import PartialFunction._
scala> unlift(condOpt(_: String) { case s if b => f(s) }) applyOrElse ("hi", g)
res0: String = f+hi
scala> b = false
b: Boolean = false
scala> unlift(condOpt(_: String) { case s if b => f(s) }) applyOrElse ("hi", g)
res1: String = g+hi

Understanding a Scala function from Play framework zentask example

This is a function in the zentask example in Application.scala.
I'm trying to understand it...
What does the f: => String mean?
What about the chaining of f: => String => Request[AnyContent] => Result
/**
* Action for authenticated users.
*/
def IsAuthenticated(f: => String => Request[AnyContent] => Result) =
Security.Authenticated(username, onUnauthorized) { user =>
Action(request => f(user)(request))
}
A parameter of the form fn: => String represents a 'generator' (either a function or a value) that returns (or is) a String, so, for example, you might have a method defined as
def myMethod(fn: => String): String = "Fn output = " + fn
and call this as follows (the return types I use here can typically be inferred by the compiler, I'm just adding them for pedagogical purposes):
def myFn: String = "Hello!"
// Alternatively: def myFn(): String = "Hello!"
// or: val myFn: () => String = "Hello!"
// or most simply: val myString = "Hello!"
val output = myMethod(myFn) // output = "Fn output = Hello!"
Building on this, we can define a method that takes a function that turns a String into an Int, eg:
def my2ndMethod(fn: String => Int): Int = fn("4")
and call it as follows:
def my2ndFn(input: String) = 5 * input.toInt
// Alternatively: val my2ndFn: String => Int = input => 5 * input.toInt
val output2 = my2ndMethod(my2ndFn _) // output2 = 20
In the case you provide, you have a more complicated entity: something that returns (or is) a function that takes a String and returns a further function that in turn takes a Request[AnyContent] and (finally) returns a Result (phew!).
You can also think of this as taking a function defined and used as follows:
def authFn(username: String)(request: Request[AnyContent]): Result
val authenticatedResult = IsAuthenticated(authFn _)
Actually it is a bit tricky to figure out how the operator associates:
f: => String => Request[AnyContent] => Result
is the same as
f: (=> String) => (Request[AnyContent] => Result)
So f is a function that takes a => String and returns a function that takes a request and returns a result. As I indicated in my comment, have a look at Need plain english translation of the following scala snippet for an explanation of some of what's going on.
So why have => String as the first argument versus just String? My guess is that it comes into play if you intended the user to pass a function that has its first argument by name (meaning it is evaluated every time it is needed).
So say you have a method g:
def g(s: => String): String => String = arg => s + arg
If you want to write a method m that takes the method g as an argument, then you need to write it like this:
def m(f: (=> String) => (String => String)) = f("a")("b")
m(g) // compiles
If you write it like this:
def n(f: String => (String => String)) = f("a")("b")
n(g) // does not compile
// found : => String => (String => String)
// required: String => (String => String)