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.
Related
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.
Here is a function to memoize /cache intermediate result :
def memoize[I, O](f: I => O) = new scala.collection.mutable.HashMap[I, O]() {
override def apply(key: I): O = getOrElseUpdate(key, f(key))
}
This works fine for code like below,
val double: Int=>Int = memoize {
_*2
}
However, when I try to use tuple as input parameter(I) it shows compile time error,
val isGivenNumIsHead:(List[Int], Int) => Boolean = memoize {
case (Nil, _) => false
case (a:: as, n) => a == n
}
Compile time error is :
Expression of type mutable.HashMap[Nothing, Boolean] {def apply(key: Nothing): Boolean} doesn't conform to expected type (List[Int], Int) => Boolean
Is this something related to erasure.
How do i fix it ?
I am assuming you want to use the tuple as the key in the HashMap. With that in mind, here is the explanation.
The actual return type of memoize is scala.collection.mutable.HashMap[_,_] . That is being assigned to double which is of type Int => Int or Function1[Int,Int] ( a function that takes an integer and gives an interger). The compiler doesnt throw an error because mutable.HashMap extends scala.collection.mutable.MapLike which in turn extends scala.collection.MapLike which in turn extends scala.PartialFunction[A, B] which in turn extends scala.Function1[A, B]. Hence there is no compilation error.
On the other hand, the syntax for functions taking one parameter and returning one value is val functionName : A => B = a => {return b} or can be written as val function : (A) => B = a => {return b} or val function: (A => B) = a => {return b}. You have used the second method. In that case, the value of A should be of single type. You have used List[Int],Int which is not a single type. Note that I intentionally removed the brackets. So in order to make that as a single type and to pass it as a tuple, you have to use one more set of brackets. The correct syntax would be
val isGivenNumIsHead:((List[Int], Int)) => Boolean = memoize {
case (Nil, _) => false
case (a:: as, n) => a == n
}
Note the usage of additional brackets to make it a tuple.
Say I have a map: Map[Int, String]. How would I get the value [String] with the lowest key [Int]. I've been trying to implement this functionally, but just can't figure out how to do this.
The following code will get you a value with a lowest key (ignoring some corner cases).
def lowestKeyMember[A](m: Map[Int,A]): A = m(m.keys.min)
This will break ties arbitrarily and throw on an empty map. If you need to do this operation frequently and/or on large maps, you should look into SortedMap.
Maps are not normally sorted. You could however use a SortedMap, then the map will be sorted and the first value will be the head. All you need to do is retrieve the head.
map.head()
Come on, people! "Functionally" is code word for "folding".
scala> val m = Map(1->"eins",2->"zwei",3->"drei")
m: scala.collection.immutable.Map[Int,String] = Map(1 -> eins, 2 -> zwei, 3 -> drei)
scala> m.foldLeft(Int.MaxValue -> "") { case (min,p) => if (min._1 <= p._1) min else p }
res0: (Int, String) = (1,eins)
But an 8-char operator?
Let's see, is that enough parens? Don't tell me -> is like - and /: is like /.
scala> (Int.MaxValue -> "" /: m) { case (min,p) => if (min._1 <= p._1) min else p }
<console>:9: error: missing arguments for method /: in trait TraversableOnce;
follow this method with `_' if you want to treat it as a partially applied function
(Int.MaxValue -> "" /: m) { case (min,p) => if (min._1 <= p._1) min else p }
^
Oh, well, OK.
scala> ((Int.MaxValue -> "") /: m) { case (min,p) => if (min._1 <= p._1) min else p }
res2: (Int, String) = (1,eins)
Or,
scala> import math.Ordering.Implicits._
import math.Ordering.Implicits._
scala> ((Int.MaxValue -> "") /: m) { case (min,p) if min <= p => min case (_, p) => p }
res5: (Int, String) = (1,eins)
A variant of the _.keys.min solution that works with Options (i.e. will not throw on an empty map):
scala> val a : Map[Int, String]=Map(1 -> "1", 2 -> "2")
a: Map[Int,String] = Map(1 -> 1, 2 -> 2)
scala> val b : Map[Int, String]=Map()
b: Map[Int,String] = Map()
scala> def valueForMinKey[K,V](a : Map[K,V])(implicit cmp : Ordering[K]) = a.keys.reduceOption(cmp.min(_, _)).map(a(_))
valueForMinKey: [K, V](a: Map[K,V])(implicit cmp: Ordering[K])Option[V]
scala> valueForMinKey(a)
res27: Option[String] = Some(1)
scala> valueForMinKey(b)
res28: Option[String] = None
In this example, the implicit parameter cmp will be satisfied by Ordering.Int. The example will work with any Map where the keys can be ordered (and a matching implict can be found by the compiler).
Suppose I have a list of functions as so:
val funcList = List(func1: A => T, func2: B => T, func2: C => T)
(where func1, et al. are defined elsewhere)
I want to write a method that will take a value and match it to the right function based on exact type (match a: A with func1: A => T) or throw an exception if there is no matching function.
Is there a simple way to do this?
This is similar to what a PartialFunction does, but I am not able to change the list of functions in funcList to PartialFunctions. I am thinking I have to do some kind of implicit conversion of the functions to a special class that knows the types it can handle and is able to pattern match against it (basically promoting those functions to a specialized PartialFunction). However, I can't figure out how to identify the "domain" of each function.
Thank you.
You cannot identify the domain of each function, because they are erased at runtime. Look up erasure if you want more information, but the short of it is that the information you want does not exist.
There are ways around type erasure, and you'll find plenty discussions on Stack Overflow itself. Some of them come down to storing the type information somewhere as a value, so that you can match on that.
Another possible solution is to simply forsake the use of parameterized types (generics in Java parlance) for your own customized types. That is, doing something like:
abstract class F1 extends (A => T)
object F1 {
def apply(f: A => T): F1 = new F1 {
def apply(n: A): T = f(n)
}
}
And so on. Since F1 doesn't have type parameters, you can match on it, and you can create functions of this type easily. Say both A and T are Int, then you could do this, for example:
F1(_ * 2)
The usual answer to work around type erasure is to use the help of manifests. In your case, you can do the following:
abstract class TypedFunc[-A:Manifest,+R:Manifest] extends (A => R) {
val retType: Manifest[_] = manifest[R]
val argType: Manifest[_] = manifest[A]
}
object TypedFunc {
implicit def apply[A:Manifest, R:Manifest]( f: A => R ): TypedFunc[A, R] = {
f match {
case tf: TypedFunc[A, R] => tf
case _ => new TypedFunc[A, R] { final def apply( arg: A ): R = f( arg ) }
}
}
}
def applyFunc[A, R, T >: A : Manifest]( funcs: Traversable[TypedFunc[A,R]] )( arg: T ): R = {
funcs.find{ f => f.argType <:< manifest[T] } match {
case Some( f ) => f( arg.asInstanceOf[A] )
case _ => sys.error("Could not find function with argument matching type " + manifest[T])
}
}
val func1 = { s: String => s.length }
val func2 = { l: Long => l.toInt }
val func3 = { s: Symbol => s.name.length }
val funcList = List(func1: TypedFunc[String,Int], func2: TypedFunc[Long, Int], func3: TypedFunc[Symbol, Int])
Testing in the REPL:
scala> applyFunc( funcList )( 'hello )
res22: Int = 5
scala> applyFunc( funcList )( "azerty" )
res23: Int = 6
scala> applyFunc( funcList )( 123L )
res24: Int = 123
scala> applyFunc( funcList )( 123 )
java.lang.RuntimeException: Could not find function with argument matching type Int
at scala.sys.package$.error(package.scala:27)
at .applyFunc(<console>:27)
at .<init>(<console>:14)
...
I think you're misunderstanding how a List is typed. List takes a single type parameter, which is the type of all the elements of the list. When you write
val funcList = List(func1: A => T, func2: B => T, func2: C => T)
the compiler will infer a type like funcList : List[A with B with C => T].
This means that each function in funcList takes a parameter that is a member of all of A, B, and C.
Apart from this, you can't (directly) match on function types due to type erasure.
What you could instead do is match on a itself, and call the appropriate function for the type:
a match {
case x : A => func1(x)
case x : B => func2(x)
case x : C => func3(x)
case _ => throw new Exception
}
(Of course, A, B, and C must remain distinct after type-erasure.)
If you need it to be dynamic, you're basically using reflection. Unfortunately Scala's reflection facilities are in flux, with version 2.10 released a few weeks ago, so there's less documentation for the current way of doing it; see How do the new Scala TypeTags improve the (deprecated) Manifests?.
How does foldRight[B](B) from scaladoc match the actual call foldRight(0)
args is an array of integers in string representation
val elems = args map Integer.parseInt
elems.foldRight(0) (_ + _)
Scaladoc says:
scala.Iterable.foldRight[B](B)((A, B) => B) : B
Combines the elements of this list together using the binary function f, from right to left, and starting with the value z.
#note Will not terminate for infinite-sized collections.
#return f(a0, f(a1, f(..., f(an, z)...))) if the list is [a0, a1, ..., an].
And not so imporant what do the periods after f(an, z) mean?
As Steve said, the "..." are just ellipsis, indicating that a variable number of parameters that are not being shown.
Let's go to the Scaladoc, and show this step by step:
def foldRight[B](z: B)(op: (B, A) ⇒ B): B
That doesn't show enough. What is A? That is defined in the Iterable class (or whatever other class it is defined for):
trait Iterable[+A] extends AnyRef // Scala 2.7
trait Iterable[+A] extends Traversable[A] with GenericTraversableTemplate[A, Iterable[A][A]] with IterableLike[A, Iterable[A]] // scala 2.8
Ok, so A is the type of the collection. In your example, A would stand for Int:
val elems = args map Integer.parseInt
Next, [B]. That's a type parameter. Basically, the following two calls are identical in practice, but the first has the type parameter inferred by the compiler:
elems.foldRight(0) (_ + _)
elems.foldRight[Int](0) (_ + _)
If you used 0L instead of 0, then B would stand for Long instead. If you passed a "" instead of 0, then B would stand for String. You can try these out, they all will work.
So, B is Int and z is 0. Note that there are two sets parenthesis in the declaration. That means the function is curried. It receives two sets of parameters, beyond, as well as the type parameter ([B]). What that means is that you can ommit the second set of parameter, and that will return a function which takes that second set of parameter, and returns the expected result. For example:
val elemsFolder: ((Int, Int) => Int) => Int = elems.foldRight(0)
Which you could then call like this:
elemsFolder(_ + _)
Anyway, the second set receives op, which is expected to be of type (B, A) => B. Or, in other words, a function which receives two parameters -- the first being the same type as z, and the second being the same type as the type of the collection -- and returns a result of the same type as the first parameter. Since both A and B are Int, it will be a function of (Int, Int) => Int. If you passed "", then it would be a function of type (String, Int) => String.
Finally, the return type of the collection is B, which means whatever is the type of z, that will be the type returned by foldRight.
As for how foldRight works, it goes a bit like this:
def foldRight[B](z: B)(op: (B, A) => B): B = {
var acc: B = z
var it = this.reverse.elements // this.reverse.iterator on Scala 2.8
while (!it.isEmpty) {
acc = op(acc, it.next)
}
return acc
}
Which, I hope should be easy enough to understand.
Everything you need to know about foldLeft and foldRight can be gleaned from the following:
scala> List("1", "2", "3").foldRight("0"){(a, b) => "f(" + a + ", " + b + ")"}
res21: java.lang.String = f(1, f(2, f(3, 0)))
scala> List("1", "2", "3").foldLeft("0"){(a, b) => "f(" + a + ", " + b + ")"}
res22: java.lang.String = f(f(f(0, 1), 2), 3)