Force grouping of ascription on underscore in scala - scala

I am trying to do:
MyObject.myMethod(_:MyType.myAttribute)
This fails with
type myAttribute is not a member of object MyObject
which is correct. The problem is that I want to call myMethod on myAttribute of _:MyType, not ascribe MyType:myAttribute to _. Can I somehow group the type ascription _:MyType? (_:MyType).myAttribute returns type MyType => classOf(myAttribute), which is not what I want.
Edit: I changed the title and text of this post to no longer refer to this as the associativity of the dot, which I believe was not correct.

Are you trying to create function (m: MyType) => MyObject.myMethod(m.myAttribute) using underscore?
If so, the problem is that MyObject.myMethod((_:MyType).myAttribute) means MyObject.myMethod((m:MyType) => m.myAttribute).
You can use infix notation:
MyObject myMethod (_:MyType).myAttribute
Proof it works:
scala> case class MyType(myAttribute: Int)
defined class MyType
scala> object MyObject {
| def myMethod(a: Int) = a.toString
| }
defined module MyObject
scala> MyObject myMethod (_:MyType).myAttribute
res0: MyType => java.lang.String = <function1>
scala> res0(MyType(1))
res1: java.lang.String = 1
scala> MyObject myMethod (MyType(1))
<console>:1: error: type mismatch;
found : MyType
required: Int
MyObject myMethod (_:MyType)
^

I'm not sure whether this illustrates or answers your question, but it's true.
My guess is that you expected your a.b(_.i) to be an anon func after you add an ascription (to type the parameter).
But the subexpr foils you by there is no other expression of syntactic category Expr which is properly contained in e and which itself properly contains u. (SLS 6.23)
Also, you can use scalac -Xprint:parser to see how it's taken.
object Foo {
def m(k: Int) = 7 * k
}
class Bar {
val i = 5
val What = i
}
object Bar {
type What = Int
}
object Test extends App {
Foo.m(_:Bar.What)
// this is not anon func placeholder syntax...
//Foo.m((_:Bar).What) // _ is in a subexpr
//Foo.m(_.i)
// ...for this
val f = (x: Bar) => Foo.m(x.i)
// InfixExpr is ok
val g = Foo m (_: Bar).i
val b = new Bar
println(f(b))
println(g(b))
}
Contrast, to illustrate what is being restricted:
scala> val f: (Int,Int)=>Int = _+_
f: (Int, Int) => Int = <function2>
scala> val g: Int=>Int = if (_ > 0) 1 else 2
<console>:7: error: missing parameter type for expanded function ((x$1) => x$1.$greater(0))

List(1,2,3).map((i: Int) => i * i)
EDIT
List(1,2,3).map((_: Int).unary_-)
EDIT 2
implicit class MyAttribute(i: Int) { def myMethod() = i * i }
List(1,2,3).map((_: Int).myMethod.unary_-)
Explanation
I used implicit class (Scala-2.10) to add myMethod on Int, after that unary "-" operation executed on result. You could add something like def wrap: MyAttribute to MyAttribute, and use it like (_: Int).wrap.method1.method2.method3.result.abs, for example.

Related

Combine a PartialFunction with a regular function

So, suppose, I want to provide a "catch all" fall back for a PartialFunction:
val foo: PartialFunction[Int, String] = { case 1 => "foo" }
val withDefault = foo orElse { _.toString }
This does not compile: missing parameter type for expanded function ((x$1) => x$1.toString).
This:
val withDefault = foo orElse { case x: Int => x.toString }
Does not compile either (same error).
This:
val withDefault = foo orElse { (x: Int) => x.toString }
fails with type mismatch; found : Int => String; required: PartialFunction[?,?]
The only way I could find to make it work is to spell out the whole thing:
val withDefault = foo orElse PartialFunction[Int, String] { _.toString }
Is there any better syntax for this? I mean, one without having to tell it that I am passing a partial function from int to string to where it expects to receive a partial function from in to string. This is not ambiguous at all, why do I have to do this?
Maybe you need applyOrElse:
val withDefault = foo.applyOrElse(_: Int, (_: Int).toString)
Or maybe you would like something like this:
implicit class PartialFunToFun[A,B](val f: PartialFunction[A,B]) extends AnyVal {
def withDefault(bar: A => B) = f.applyOrElse[A,B](_: A, bar)
}
and use it: foo.withDefault(_.toString)(1)
Also if you want to get just another PartialFunction you can use the next syntax:
val withDefault = foo.orElse[Int, String]{case x => x.toString}
The errors you encountered for the first two are not specific to orElse. They also occur when you attempt to define the same functions separately.
scala> { _.toString }
<console>:12: error: missing parameter type for expanded function ((x$1: <error>) => x$1.toString)
{ _.toString }
scala> { case x: Int => x.toString }
<console>:12: error: missing parameter type for expanded function
The argument types of an anonymous function must be fully known. (SLS 8.5)
Expected type was: ?
{ case x: Int => x.toString }
^
For the last one, you are defining a function rather than a PartialFunction, thus leading to the "type mismatch" since orElse expects a PartialFunction to be passed.
scala> { (x: Int) => x.toString }
res3: Int => String = $$Lambda$1127/2044272973#3d5790ea
The final thing I'll add is that orElse is meant as a way to union two PartialFunctions. _.toString in itself is not a PartialFunction, though you could create a PartialFunction that uses it. To me it sounds like you want to have a "default" result for all the values that foo is not defined for, so I think you actually want applyOrElse instead since that is its use case. See the API to learn more.

type inference fails in a generic scala function

consider a simple function that operates on collections distinctBy, which, like distinct remove "duplicates" (which are not necessary actual duplicates):
import scala.collection.TraversableLike
import scala.collection.generic.CanBuildFrom
import scala.collection.mutable.{Set=>MSet}
def distinctBy[T,R,Coll]
(xs: Coll)
(f: T => R)
(implicit ev: Coll <:< TraversableLike[T,Coll],
cbf: CanBuildFrom[Coll,T,Coll]): Coll = {
val builder = cbf(xs)
builder.sizeHint(xs.size)
val seen = MSet.empty[R]
xs.foreach { elem =>
if(!seen(f(elem))){
builder += elem
}
}
builder.result()
}
now consider a class to use it on:
case class X(i: Int, j: Int)
using this function naively fails:
scala> distinctBy(Vector(X(1,2),X(3,2),X(1,1),X(2,2)))(_.i)
<console>:14: error: missing parameter type for expanded function ((x$1) => x$1.i)
distinctBy(Vector(X(1,2),X(3,2),X(1,1),X(2,2)))(_.i)
^
<console>:14: error: Cannot construct a collection of type scala.collection.immutable.Vector[X] with elements of type Any based on a collection of type scala.collection.immutable.Vector[X].
distinctBy(Vector(X(1,2),X(3,2),X(1,1),X(2,2)))(_.i)
^
but if I help the type inferencer, this works:
scala> distinctBy(Vector(X(1,2),X(3,2),X(1,1),X(2,2)))((x:X) => x.i)
res1: scala.collection.immutable.Vector[X] = Vector(X(1,2), X(3,2), X(1,1), X(2,2))
scala> distinctBy[X,Int,Vector[X]](Vector(X(1,2),X(3,2),X(1,1),X(2,2)))(_.i)
res2: scala.collection.immutable.Vector[X] = Vector(X(1,2), X(3,2), X(1,1), X(2,2))
to my best understanding, since the function is given in a second argument list, the type inferencer should have picked up that it's a function from X to something. and since X has a member i of type Int, all should have been OK with the first try. so, what am I missing here?
This simplified version works fine for me:
object A {
def f1[T, R](l: List[T])(f: T=>R) = None
case class X(i: Int, j: Int)
f1(List(X(1,1),X(2,1)))(_.i)
}
As you can see collection in first parameter list has T type that allows scala inference type in second arguments list.
So you need build somehow dependencies between Col and T in your example. Not sure if third implicits parameters list helps here.
UPD.
Looks weird but seems it works:
object A {
def f1[T, R, Col[Z]](l: Col[T])(f: T => R) = None
case class X(i: Int, j: Int)
f1(List(X(1,1),X(2,1)))(_.i)
}
UPD2.
Rewritten sample from question.
import scala.collection.TraversableLike
import scala.collection.generic.CanBuildFrom
import scala.collection.mutable.{Set=>MSet}
def distinctBy[T,R,Coll[Z]]
(xs: Coll[T])
(f: T => R)
(implicit ev: Coll[T] <:< TraversableLike[T,Coll[T]],
cbf: CanBuildFrom[Coll[T],T,Coll[T]]): Coll[T] = {
val builder = cbf(xs)
builder.sizeHint(xs.size)
val seen = MSet.empty[R]
xs.foreach { elem =>
if(!seen(f(elem))){
builder += elem
seen.add(f(elem))
}
}
builder.result()
}
case class X(i: Int, j: Int)
distinctBy(Vector(X(1,2),X(1,2),X(3,2),X(1,1),X(2,2)))(_.i)
distinctBy(Map("1" -> X(1,2), "2" -> X(1,2), "3" -> X(3,2)))(_._2.i)

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

In Scala, can generic type parameters be used with *function* definitions?

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/

Can I name a tuple (define a structure?) in Scala 2.8?

It does not look very good for me to always repeat a line-long tuple definition every time I need it. Can I just name it and use as a type name? Would be nice to name its fields also instead of using ._1, ._2 etc.
Regarding your first question, you can simply use a type alias:
type KeyValue = (Int, String)
And, of course, Scala is an object-oriented language, so regarding your second about how to specialize a tuple, the magic word is inheritance:
case class KeyValue(key: Int, value: String) extends (Int, String)(key, value)
That's it. The class doesn't even need a body.
val kvp = KeyValue(42, "Hello")
kvp._1 // => res0: Int = 42
kvp.value // => res1: String = "Hello"
Note, however, that inheriting from case classes (which Tuple2 is), is deprecated and may be disallowed in the future. Here's the compiler warning you get for the above class definition:
warning: case class class KV has case class ancestor class Tuple2. This has been deprecated for unduly complicating both usage and implementation. You should instead use extractors for pattern matching on non-leaf nodes.
Type alias is fine for naming your Tuple, but try using a case class instead. You will be able to use named parameters
Example with tuple:
def foo(a : Int) : (Int, String) = {
(a,"bar")
}
val res = foo(1)
val size = res._1
val name= res._2
With a case class:
case class Result( size : Int , name : String )
def foo(a : Int) : Result = {
Result(a,"bar")
}
val res = foo(1)
val size = res.size
val name= res.name
Here's a solution that creates a type alias and a factory object.
scala> type T = (Int, String)
defined type alias T
scala> object T { def apply(i: Int, s: String): T = (i, s) }
defined module T
scala> new T(1, "a")
res0: (Int, String) = (1,a)
scala> T(1, "a")
res1: (Int, String) = (1,a)
However as others have mentioned, you probably should just create a case class.
Although as others have said, explicit (case) classes are best in the general sense.
However for localized scenarios what you can do is to use the tuple extractor to improve code readability:
val (first, second) = incrementPair(3, 4)
println(s"$first ... $second")
Given a method returning a tuple:
def incrementPair(pair: (Int, Int)) : (Int, Int) = {
val (first, second) = pair
(first + 1, second + 1)
}