I wonder why there doesn't exist a literal for partial function types. I have to write
val pf: PartialFunction[Int, String] = {
case 5 => "five"
}
where an literal like :=> would be shorter:
val pf: Int :=> String = {
case 5 => "five"
}
Partial functions are often used and in Scala already some "special" feature, so why no special syntax for it?
Probably in part because you don't need a literal: you can always write your own :=> as a type infix operator if you want more concise syntax:
scala> type :=>[A, B] = PartialFunction[A, B]
defined type alias $colon$eq$greater
scala> val pf: Int :=> String = { case 5 => "five" }
pf: :=>[Int,String] = <function1>
scala> pf.isDefinedAt(0)
res0: Boolean = false
scala> pf.isDefinedAt(5)
res1: Boolean = true
I'm not one of the designers of the Scala language, though, so this is more or less a guess about the "why?". You might get better answers over at the scala-debate list, which is a more appropriate venue for language design questions.
Related
Can someone explain how and when to use the triple caret ^^^ (vs the double caret ^^) when designing scala parser combinators? And also when / how to use the parser.into() method (>>).
I'll begin with an example using Scala's Option type, which is similar in some important ways to Parser, but can be easier to reason about. Suppose we have the following two values:
val fullBox: Option[String] = Some("13")
val emptyBox: Option[String] = None
Option is monadic, which means (in part) that we can map a function over its contents:
scala> fullBox.map(_.length)
res0: Option[Int] = Some(2)
scala> emptyBox.map(_.length)
res1: Option[Int] = None
It's not uncommon to care only about whether the Option is full or not, in which case we can use map with a function that ignores its argument:
scala> fullBox.map(_ => "Has a value!")
res2: Option[String] = Some(Has a value!)
scala> emptyBox.map(_ => "Has a value!")
res3: Option[String] = None
The fact that Option is monadic also means that we can apply to an Option[A] a function that takes an A and returns an Option[B] and get an Option[B]. For this example I'll use a function that attempts to parse a string into an integer:
def parseIntString(s: String): Option[Int] = try Some(s.toInt) catch {
case _: Throwable => None
}
Now we can write the following:
scala> fullBox.flatMap(parseIntString)
res4: Option[Int] = Some(13)
scala> emptyBox.flatMap(parseIntString)
res5: Option[Int] = None
scala> Some("not an integer").flatMap(parseIntString)
res6: Option[Int] = None
This is all relevant to your question because Parser is also monadic, and it has map and flatMap methods that work in very similar ways to the ones on Option. It also has a bunch of confusing operators (which I've ranted about before), including the ones you mention, and these operators are just aliases for map and flatMap:
(parser ^^ transformation) == parser.map(transformation)
(parser ^^^ replacement) == parser.map(_ => replacement)
(parser >> nextStep) == parser.flatMap(nextStep)
So for example you could write the following:
object MyParser extends RegexParsers {
def parseIntString(s: String) = try success(s.toInt) catch {
case t: Throwable => err(t.getMessage)
}
val digits: Parser[String] = """\d+""".r
val numberOfDigits: Parser[Int] = digits ^^ (_.length)
val ifDigitsMessage: Parser[String] = digits ^^^ "Has a value!"
val integer: Parser[Int] = digits >> parseIntString
}
Where each parser behaves in a way that's equivalent to one of the Option examples above.
If I define a simple stringToInt function and store it as a val, everything works as expected, e.g.
scala> def stringToInt1: (String => Int) = _.toInt
stringToInt1: String => Int
scala> stringToInt1("1")
res0: Int = 1
However, if I then make that implicit, it causes a stack overflow:
scala> implicit def stringToInt2: (String => Int) = _.toInt
stringToInt2: String => Int
scala> stringToInt2("1")
java.lang.StackOverflowError
at .stringToInt2(<console>:7)
at $anonfun$stringToInt2$1.apply(<console>:7)
at $anonfun$stringToInt2$1.apply(<console>:7)
...
At first I suspected that this was because the underscore wasn't resolving to what I expected, but that's not the case, as this style of implicit val works fine for the following simple function:
scala> implicit def plusTwo: (Int => Int) = _ + 2
plusTwo: Int => Int
scala> plusTwo(2)
res2: Int = 4
If I define the parameter explicitly, no stack overflow:
scala> implicit def stringToInt3(s: String) = s.toInt
stringToInt3: (s: String)Int
scala> stringToInt3("1")
res3: Int = 1
(If trying this yourself and this last case stack overflows, restart the scala console and redo this last step)
So my question is, why is the original implicit not correctly resolving?
Edit
Ok digging a little deeper here, it seems that the problem is with the implicit conversion from String to StringOps. If we cut that out, it works fine:
scala> import scala.collection.immutable.StringOps
import scala.collection.immutable.StringOps
scala> implicit def stringToInt4: (String => Int) = new StringOps(_).toInt
stringToInt4: String => Int
scala> stringToInt4("1")
res4: Int = 1
But why would that implicit conversion be causing the issue?
Adding to the other replies.
There is no toInt method on String. Scala has to find an implicit conversion that will yield a type that has a toInt method.
Usually the StringOps conversion provides this toInt.
However Int has a toInt too, so scala finds your conversion from String => Int and decides that it has precedence over the StringOps conversion, thus applying it recursively.
This is why StringToInt4 works, as you explicitly tell the compiler what conversion you want. Maybe you could write it as: implicit def stringToInt5: (StringOps => Int) = _.toInt or check how implicits are resolved and how one takes precedence over the other.
Note what you are doing here:
scala> def stringToInt1: (String => Int) = _.toInt
stringToInt1: String => Int
You are defining a method (using def) that takes no parameters and returns a function from String to Int. Are you doing it this way on purpose, or is it just because you don't exactly understand the syntax?
You could have created a val instead:
val stringToInt1: (String => Int) = _.toInt
Now, stringToInt1 is a val that contains a function to convert String to Int.
With your stringToInt2, Scala is recursively applying the method. I don't know why it does that in the case of stringToInt2 but not with plusTwo.
Note that stringToInt3 is not the same thing as stringToInt1 and stringToInt2. It's a method that takes a String and returns an Int, not a method that takes no parameters and returns a function from String to Int.
I don't think this code should work, but it does (in Scala 2.10):
scala> ((i: Int) => i.toString match {
| case s if s.length == 2 => "A two digit number"
| case s if s.length == 3 => "A three digit number"
| }): PartialFunction[Int,String]
res0: PartialFunction[Int,String] = <function1>
// other interactions omitted
scala> res0.orElse(PartialFunction((i: Int) => i.toString))
res5: PartialFunction[Int,String] = <function1>
scala> res5(1)
res6: String = 1
How does it work? I would expect a MatchError to be thrown inside res0.
The Scala language specification does not seem to explicitly document how res0 should be interpreted.
The trick is that the compiler is not interpreting your definition as a total function converted to a partial function -- it's actually creating a partial function in the first place. You can verify by noting that res0.isDefinedAt(1) == false.
If you actually convert a total function to a partial function, you will get the behavior you expected:
scala> PartialFunction((i: Int) => i.toString match {
| case s if s.length == 2 => "A two digit number"
| case s if s.length == 3 => "A three digit number"
| })
res0: PartialFunction[Int,String] = <function1>
scala> res0 orElse ({ case i => i.toString }: PartialFunction[Int, String])
res1: PartialFunction[Int,String] = <function1>
scala> res1(1)
scala.MatchError: 1 (of class java.lang.String)
// ...
In this example, PartialFunction.apply treats its argument as a total function, so any information about where it's defined is lost.
orElse is defined on PartialFunction so that the argument is treated as a fallback for the cases when the original is not defined. See the API.
You say that if res0 does not match, you want to try your other pf instead. How this essentially works is:
if (res0.isDefinedAt(1)) {
res0(1)
} else {
other(1)
}
The orElse call creates an instance of OrElse, which inherits from PartialFunction: https://github.com/scala/scala/blob/master/src/library/scala/PartialFunction.scala#L159
When you now call apply on this OrElse, it will call f1.applyOrElse(x, f2): https://github.com/scala/scala/blob/master/src/library/scala/PartialFunction.scala#L162
This will call if (isDefinedAt(x)) apply(x) else f2(x): https://github.com/scala/scala/blob/master/src/library/scala/PartialFunction.scala#L117-L118
Therefore you will only get a MatchError, when neither of the pf's matches.
I've asked a couple of questions regarding reflection in Scala the last few days, because it still seems new to me.
The new one is actually two questions that are related :
How would you create a function that returns a different result based on the input type?
Can you do the same with the TypeSymbol and Type objects returned by the reflection API?
Example (does not compile, but that's roughly how I want it to work) :
def result[T <: String] = "STRING"
def result[T <: Int] = "INT"
result[String] // Returns "STRING"
result[Int] // Returns "INT"
val type_symbol: Type = ... // Get a Type object from a reflection
type_symbol match {
case Int => "INT"
case String => "STRING"
case _ => "OTHER"
}
Maybe it's something like this you're looking for?
import scala.reflect.runtime.universe._
def someStringBasedOnAType[T: TypeTag] = typeOf[T] match {
case t if t =:= typeOf[Int] => "INT"
case t if t =:= typeOf[String] => "STRING"
case _ => "OTHER"
}
Results:
scala> someStringBasedOnAType[String]
res11: String = STRING
scala> someStringBasedOnAType[Float]
res12: String = OTHER
scala> someStringBasedOnAType[Int]
res13: String = INT
Be aware, however, that using TypeTags is thread-unsafe a the moment. As far as I know this should change in a few months, probably in Scala 2.10.2 (see SI-6240)
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/