I'm just going over some Scala tutorials on the Internet and have noticed in some examples the author used both => and -> in a HOF(Higher Order Function).
Example:
val vec = Vector("hello", "world").map(s => s -> s.length)
// vec: scala.collection.immutable.Vector[(String, Int)] =
// Vector((hello,5), (world,5))
What is the difference between => and -> in Scala?
-> it used to associate key with a value by using implicit conversion for example tuple, map etc.
scala> 1 -> 2
res0: (Int, Int) = (1,2)
scala> val map = Map("x" -> 12, "y" -> 212)
Its basically just take the item on the left and map it to the item on the right
It converts any type into an instance of "ArrowAssoc" using implicit conversion
implicit def any2ArrowAssoc[A](x: A): ArrowAssoc[A] = new ArrowAssoc(x)
class ArrowAssoc[A](x: A) {
def -> [B](y: B): Tuple2[A, B] = Tuple2(x, y)
}
=> is a syntax provided by the language itself to create instance of function using call-by-name.
It passes value name inside the method for example:
`def f(x:Int => String) {}` function take argument of type Int and return String
You can also pass no argument like below
() => T means it doesn't take any argument but return type T.
-> is used for Method provided by implicit conversion & key->value creates a tuple (key,value).
=> is used for function types, function literals, and import renaming.
Related
I have a very simple piece of code that I am not able to get grasp of. I am reading function literals, and methods. I am doing this in repl.
scala> val v = (a:Int, b:Int, c:Int) => {a+b+c}
v: (Int, Int, Int) => Int = $$Lambda$1368/1731643198#4ae730ca
scala> val v1 = v(1,2,_:Int)
v1: Int => Int = $$Lambda$1369/903167315#93d6f4
scala> v1 (10)
res29: Int = 13
scala>
scala> val v2 = v _
v2: () => (Int, Int, Int) => Int = $$Lambda$1370/5485285#7dd5d17a
scala> val v3 = v2()
v3: (Int, Int, Int) => Int = $$Lambda$1368/1731643198#4ae730ca
scala> val v4 = v3(1,2,3)
v4: Int = 6
scala> def sumMe(a:Int, b:Int, c:Int) = { a+b+c}
sumMe: (a: Int, b: Int, c: Int)Int
scala> val v7 = sumMe _
v7: (Int, Int, Int) => Int = $$Lambda$1371/906350712#6c86938f
scala> v7(1,2,3)
res30: Int = 6
I need some help in understanding on what happens above. I will start from the bottom of the code. When I create the method sumMe and assign it to "v7" with "_" on the right, I know I am not executing the method. The output of val v7= sumMe_ is quite clear to me as it simply tells me that v7 will take 3 params, and return an int. It feels OK so far.
Now when I go to my `val v1 = v(1,2,_:Int), I can still correlate that it will create a function object and assign to v1 and in fact I am using Scala
s Function1's apply method is what I view it as.
I am hoping I understand it right so far. If my understanding above is right, what causes the most confusion is val v2 = v _. And based on the output of what I see I have to call this thing differently. Basically I am not able to understand why v2 is different from v7. v2 takes no arguments and gives me a function which I can call. If that is always the case with function literals of the kind that I have defined as val v = ..., then when I do val v1 = v(1,2,:_Int) why don't I get this from scala v1:()=>Int=>Int which is similar to v2's case.
And lastly, why won't v7=sumMe _ not give me the same output as val v2 = v_
In Scala, we differentiate methods from functions. When you define sumMe, you're defining a method, while your other declarations are functions. Methods, in Scala, are non value types, meaning the method itself has no value. When you try to assign it to a value, there is an implicit conversion called eta expansion that is done to convert it to the corresponding function type. From the specification:
Method types do not exist as types of values. If a method name is used
as a value, its type is implicitly converted to a corresponding
function type.
Now that we're equipped with the knowledge of methods and functions, lets analyze what happens.
When I create the method sumMe and assign it to "v7" with "_" on the right, I know I am not executing the method
That's right. When you do sumMe _, you're using eta-expansion to convert the method to a function.
Now when I go to my val v1 = v(1, 2, _: Int), I can still correlate that
it will create a function object and assign to v1
Again, you're right. v1 is now a partially applied function of type Function1[Int, Int].
Basically I am not able to understand why v2 is different from v7.
What is v2? It is a function object which was created by partially applying an existing function object. Since this function of type Function3[Int, Int, Int, Int] is already fixed in it's parameter list, partially applying it only nests it in another function object, now of type Function0, making it a Function0[Function3[Int, Int, Int, Int]].
In Scala, functions are value that means you can assign any function in a variable. Whenever you apply placeholder("_") in front of def it will convert def into function with same input and output types. If you apply placeholder in front of value it will convert into function that take unit as input and return value as output**[() => T]**. for example:
scala> val a = 2
a: Int = 2
scala> val fun1 = a _
fun1: () => Int = <function0>
scala> def sum(a:Int, b:Int) = a+ b
sum: (a: Int, b: Int)Int
scala> val fun2 = sum _
fun2: (Int, Int) => Int = <function2>
whenever you are trying to pass partial input parameters in a "def" it will return partial applied function. For example:
scala> val fun3 = sum(1,_:Int)
fun3: Int => Int = <function1>
fun3 is called partial applied function.
There are something need to clear for function and method,
function: we use val and var to define the function, it's often is an Anonymous Function, In Scala, there are Function0, Function1, Function2 ... for these Anonymous Function, and the function type like: (T0, T1...TN) => U.
so function v actually is a Function3 with 3 parameters.
method: it's used to def to declare with method body with the parameters and return type.
For val v2 = v _ actually equals to val v2 = () => v, in there wildcard _ will expand to () => v, and v2 means it's a function to create another function(v) without parameter.So val v3 = v2() means invoke v2() to create v function, so essentially v3 equal to v.
For val v7 = sumMe _ this means convert method sumMe to a function, in there wildcard _ will expand to (a: Int, b: Int, c: Int) => sumMe(a, b, c) , so sumMe _ will create a new function that's essentially equal to v, if you use v7 _ it also will create the same function like val v2 = v _.
Reference:
Difference between method and function in Scala
I am trying to create a map of lambda functions in Scala
val identity = ((x:Any) => x)
val propmap = Map("references-count" -> identity,
"title" -> ((x:List[String]) => x(0)),
"score" -> identity,
"issued" -> ((x:List[Any]) => x(0)))
when I type propmap("score") or propmap("title") the output I get is the same: <function1>.
Running identity(10.1) returns the expected result. However
val f1 = propmap("score")
f1(10.9)
results in:
Name: Unknown Error
Message: <console>:29: error: type mismatch;
found : Double(10.9)
required: List[String]
f1(10.9)
^
StackTrace:
Seemingly the function is overwritten. Where to go for the besung immutabilty?
The problem is the type of propmap.
Scala infers the type as String, (List[String] => Any)
The reason for that is that scala needs to infer a type which matches ALL values. The String as key is obvious but for the function, it needs to find a function type which matches all functions. Since all functions have 1 parameter this would be function1.
If you look at the definition of function1 you would see it is:
trait Function1[-T1, +R] extends AnyRef
This means that it needs to find the first type to be the most constrictive. In this case this is List[String] and therefore it expects a function List[String]=>Any (this actually makes sense because you want a type you can use on ALL functions).
So scala automatically converts your identity function to be (x: List[String] => x) in practice and therefore when you try to pass it a number it fails.
Possible solutions:
The first solution as mentioned by #KotWarm would be to use asInstanceOf:
val f1 = propmap("score").asInstanceOf[Any ⇒ Any]
println(f1(10.9))
The second solution would be to rewrite the functions to use Any, for example:
val propmap = Map("references-count" -> identity,
"title" -> ((x: Any) => x.asInstanceOf[List[String]](0)),
"score" -> identity,
"issued" -> ((x: Any) => x.asInstanceOf[List[Any]](0)))
Because scalac determined the type of collection as
propmap: scala.collection.immutable.Map [String, List [String] => Any]
Determine the type of your collection explicitly so that the compiler knows what you want to get
Here is an example code
val identity = ((x:Any) => x)
val propmap = Map[String,_ => _]("references-count" -> identity,
"title" -> ((x:List[String]) => x(0)),
"score" -> identity,
"issued" -> ((x:List[Any]) => x(0)))
But to execute the methods you must cast the type
val f1 = propmap("score").asInstanceOf[Any ⇒ Any]
println(f1(10.9))
Recently I've found a code snippet:
case t # MethCall(o,m) => ((t -> input)(o)) match {
case Some(o # ObjType(_,_)) => o.retType(m)
case _ => None
}
I was interested in the next expression:
(t -> input)(o)
I know that (t -> input) is a Tuple2. But what does mean invocation (o)? I didn't find such factory method in Tuple2. So what does (t -> input)(o) mean in the code snippet?
It's not easy to guess what -> means in this context. It does not have to be a -> defined in Scala Predef/ArrowAssoc. Here are couple alternatives:
1) It can defined as a method on MethCall class:
case class MethCall(v: Int) { def ->(in: String)(other: String) = in + v + other }
scala> (MethCall(1) -> "input: ")(" ,other")
res1: String = input: 1 ,other
2) It could also be an implicit conversion from Tuple2 to a Function1 which uses apply/() method on it:
implicit def tuple2toFunct1[A, B, C](t: Tuple2[A, B]) = (v: C) => identity(v)
scala> (1 -> 2)("three")
res1: String = three
To be sure you can inspect the type of the expression in the IDE/REPL.
Given the
def sum(a: Int, b: Int) = a + b
val add7 = sum(7, _)
// compiler complains missing $x1's type for $x1 => sum(7, $x1)
val add8 = sum(8, _: Int)
// fine
And curried sum can do this without type declaration .
def sum_curry(a: Int)(b: Int) = a + b
val add9 = sum_curry(9)(_)
// fine
But it's not a generic function, what sum's parameter types can be known and it is already there.
Why cannot Scala know the $x1's type from b: Int in sum's signature?
The compiler needs to know the data types of function arguments to map a function call to exactly one function definition (out of many overloaded function definition of with same name)
It will become ambiguous if we try a reverse mapping from function definition to function call to determine the type of a parameter in function call.
Eta expression can convert this to a value type (Int, Int) => Int only when:
_ as in place of the argument of list
val f = sum _
or, you just omit the argument list.
val f :(Int, Int) => Int = sum
and specify its type.
or use each _
val f = sum(_ , _)
As you can see, sum(7, _) cannot satisfy any of above.
Is there a syntax to allow generic type parameters on function literals? I know I could wrap it in a method such as:
def createLongStringFunction[T](): (T) => Boolean = {
(obj: T) => obj.toString.length > 7
}
but then I end up needing to invoke the method for every type T and getting a new function. I looked through the language reference, and while I see that the function literal syntax is translated by the compiler to an instance of a Functionn object that itself has generic input types, it looks like the compiler magic realizes those parameters at the time of creation. I haven't found any syntax that allows me to, in effect, "leave one or more of the type parameters of Functionn unbound". What I would prefer is something along the lines of:
// doesn't compile
val longStringFunction: [T](T) => Boolean = (obj: T) => obj.toString.length > 7
Does any such thing exist? Or for that matter, what is the explicit type of an eta-expansion function when the method being expanded has generic parameters?
This is a purely contrived and useless example. Of course I could just make the function use Any here.
No, type parameters only apply to methods and not function objects. For example,
def f[T](x: T) = x //> f: [T](x: T)T
val g = f _ //> g: Nothing => Nothing = <function1>
// g(2) // error
val h: Int=>Int = f _ //> h : Int => Int = <function2>
h(2) //> res0: Int = 2
The method f cannot be converted to a polymorphic function object g. As you can see, the inferred type of g is actually Function1[Nothing, Nothing], which is useless. However, with a type hint we can construct h: Function1[Int,Int] that works as expected for Int argument.
As you say, in your example all you're requiring is the toString method and so Any would be the usual solution. However, there is call for being able to use higher-rank types in situations such as applying a type constructor such as List to every element in a tuple.
As the other answers have mentioned, there's no direct support for this, but there's a relatively nice way to encode it:
trait ~>[A[_],B[_]] {
def apply[X](a : A[X]) : B[X]
}
type Id[A] = A //necessary hack
object newList extends (Id ~> List) {
def apply[X](a : Id[X]) = List(a)
}
def tupleize[A,B, F[_]](f : Id ~> F, a : A, b : B) = (f(a), f(b))
tupleize(newList, 1, "Hello") // (List(1), List(Hello))
Since longStringFunction defined as followed is a value, which must have some given type.
val longStringFunction: (T) => Boolean = (obj: T) => obj.toString.length > 7
However, you can reuse a function object with a method:
scala> val funObj: Any => Boolean = _.toString.size > 7
funObj: Any => Boolean = <function1>
scala> def typedFunction[T]: T => Boolean = funObj
typedFunction: [T]=> T => Boolean
scala> val f1 = typedFunction[String]
f1: String => Boolean = <function1>
scala> val f2 = typedFunction[Int]
f2: Int => Boolean = <function1>
scala> f1 eq f2
res0: Boolean = true
This works because trait Function1[-T1, +R] is contravariant of type T1.
In scala, Function values are parametrically monomorphic(while methods are polymorphic)
Shapeless library introduces polymorphic function values which may be mapped over HLists and many more other features.
Please consider the following refs:
http://www.chuusai.com/2012/04/27/shapeless-polymorphic-function-values-1/
http://www.chuusai.com/2012/05/10/shapeless-polymorphic-function-values-2/