Using XScalaWT, this compiled under Scala 2.7:
class NodeView(parent: Composite) extends Composite(parent) {
var nodeName: Label = null
this.contains(
label(
nodeName = _
)
)
}
With 2.8.0 RC1, I get this error:
type mismatch; found : main.scala.NodeView required: org.eclipse.swt.widgets.Label
The types are:
label(setups: (Label => Unit)*)(parent: Composite) : Label
contains(setups: (W => Unit)*) : W
So it looks like _ now binds to the outer function instead of inner.
Is this change intentional?
UPDATE: Here is a minimized example:
Scala 2.7.7:
scala> var i = 0
i: Int = 0
scala> def conv(f: Int => Unit) = if (_:Boolean) f(1) else f(0)
conv: ((Int) => Unit)(Boolean) => Unit
scala> def foo(g: Boolean => Unit) { g(true) }
foo: ((Boolean) => Unit)Unit
scala> foo(conv(i = _))
scala> i
res4: Int = 1
Scala 2.8.0RC3:
scala> var i = 0
i: Int = 0
scala> def conv(f: Int => Unit) = if (_:Boolean) f(1) else f(0)
conv: (f: (Int) => Unit)(Boolean) => Unit
scala> def foo(g: Boolean => Unit) { g(true) }
foo: (g: (Boolean) => Unit)Unit
scala> foo(conv(i = _))
<console>:9: error: type mismatch;
found : Boolean
required: Int
foo(conv(i = _))
^
scala> foo(conv(j => i = j))
scala> i
res3: Int = 1
Interestingly enough, this works:
scala> foo(conv(println _))
1
Here is the answer I got from Lukas Rytz on the scala-user list:
Hi Alexey,
there has been a change in semantics
when we introduced named arguments. An
expression
foo(a = _)
used to be parsed as follows:
foo(x => a = x)
In 2.8, "a" is treated as a named
argument, i.e. the expression is
parsed as:
x => foo(a = x)
I will add a migration warning for
this change.
I noticed the same thing and asked on Dave's blog:
http://www.coconut-palm-software.com/the_new_visual_editor/doku.php?id=blog:simplifying_swt_with_scala#comment__930ba2f0a020203873d33decce01ebc2
No answer there yet though. Just as you're saying, it seems like the _ binds to the outer closure rather than the inner one.
Changing
nodeName = _
to
x => nodeName = x
fixes the problem.
Related
There are some discussions here about this, but I have some specific questions I wasn't able to find an answer for. So, by call-by-name, I mean =>T type, and by 0-arity function I mean () => T
I understand (I think) the conceptual difference, but probably I am missing something as I still have lots of questions:
Why do we have the concept of =>T at all if we could always use () => T?
Is there any syntax/functional limitations of each? For now I found only that => cannnot be used as a class field. Is this the only limitation?
Is the generated code always the same for both?
Should I always prefer =>T? And why?
Is it correct to call =>T a type? It looks for me like it does not have any type representation in scala.
1) It's just more handy to use it, especially inside DSLs:
def printAndGet[T](f: => T) = {
val res = f
println(res + " printed")
res
}
scala> :paste
// Entering paste mode (ctrl-D to finish)
val k = printAndGet {
val a = 5
5 * a
}
// Exiting paste mode, now interpreting.
25 printed
k: Int = 25
2) => T can only be a parameter of method or function. And actually => T and () => T aren't interchangable:
scala> def aaa(f: => String) = f
aaa: (f: => String)String
scala> val a: Function1[() => String, String] = aaa _
<console>:8: error: type mismatch;
found : (=> String) => String
required: (() => String) => String
val a: Function1[() => String, String] = aaa _
^
Thanks to #som-snytt, fоund this one:
scala> object O { def f(i: Int) = i; def f(i: => Int) = i + 1 }
defined object O
scala> O.f(5)
res12: Int = 5
scala> O.f(5: (=> Int))
<console>:1: error: no by-name parameter type allowed here
O.f(5: (=> Int))
^
Even this which should work if it compiles - but it doesn't (scala 2.11.2, 2.11.5 REPL just crashes):
scala> val k: (=> Int) => Int = O.f _
k: (=> Int) => Int = <function1>
scala> k(5) //should be 6
res18: Int = 5 //WTF?
Last one seems like a bug
3) Not exactly, if you want the same, just convert => T into () => T:
scala> def aaa(f: => String) = {f _}
aaa: (f: => String)() => String
Bytecode may also differ. For instance, compiler will more likely inline code from => T without generating lambda for it. So, the key difference is that () => T is actually an object (first class citizen), => T isn't.
4) see 1, but sometimes you may need to ensure that user knows that computation might be delayed - () => T is better then.
5) It's part of a type signature, just look at eta-expansion of:
scala> def aaa(f: => String) = {f}
aaa: (f: => String)String
scala> aaa _ //convert method into a function
res7: (=> String) => String = <function1>
scala> val a: ( => String) => String = aaa _
a: (=> String) => String = <function1>
However scala doesn't recognize it as independent type:
scala> val a: Function1[( => String), String] = aaa _
<console>:1: error: no by-name parameter type allowed here
val a: Function1[( => String), String] = aaa _
^
So I have an expensive method with this signature
def func(param: Int): \/[String, Int]
I am trying to loop over a list of params and returns \/[String, List[Int]] but stop the loop whenever the method returns -\/.
I come up with this:
scala> def func(i: Int) = {
| if( i > 1 ) { println{"!!"} ;"error".left[Int]}
| else i.right[String]
| }
func: (i: Int)scalaz.\/[String,Int]
scala> val toList = (dis: scalaz.\/[String,Int]) => {dis.map(i => List(i))}
toList: scalaz.\/[String,Int] => scalaz.\/[String,List[Int]] = <function1>
scala> val composed = (func _) andThen toList
composed: Int => scalaz.\/[String,List[Int]] = <function1>
scala> (1 to 3).toList.foldLeftM(List[Int]().right[String]){(dis, i) =>
| for{
| a <- dis
| b <- composed(i)
| } yield a |+| b
| }
<console>:17: error: no type parameters for method foldLeftM: (f: (scalaz.\/[String,List[Int]], Int) => G[scalaz.\/[String,List[Int]]])(implicit M: scalaz.Monad[G])G[scalaz.\/[String,List[Int]]] exist so that it can be applied to arguments ((scalaz.\/[String,List[Int]], Int) => scalaz.\/[String,List[Int]])
--- because ---
argument expression's type is not compatible with formal parameter type;
found : (scalaz.\/[String,List[Int]], Int) => scalaz.\/[String,List[Int]]
required: (scalaz.\/[String,List[Int]], Int) => ?G[scalaz.\/[String,List[Int]]]
(1 to 2).toList.foldLeftM(List[Int]().right[String]){(dis, i) =>
^
<console>:17: error: type mismatch;
found : (scalaz.\/[String,List[Int]], Int) => scalaz.\/[String,List[Int]]
required: (scalaz.\/[String,List[Int]], Int) => G[scalaz.\/[String,List[Int]]]
(1 to 2).toList.foldLeftM(List[Int]().right[String]){(dis, i) =>
^
What's the G[_] here and what's the correct result type in foldLeftM ?
Solved by noted two mistake I made:
misunderstood about type of initial/carried over value, it should be List[Int] instead of \/
one has to explicit declare type parameter of foldLeftM
scala> def func(i: Int) = {
| if( i > 1 ) { println{"!!"} ;"error".left[Int]}
| else i.right[String]
| }
func: (i: Int)scalaz.\/[String,Int]
scala> val toList = (dis: scalaz.\/[String,Int]) => {dis.map(i => List(i))}
toList: scalaz.\/[String,Int] => scalaz.\/[String,List[Int]] = <function1>
scala> val composed = (func _) andThen toList
composed: Int => scalaz.\/[String,List[Int]] = <function1>
scala> val f = (dis: List[Int], i: Int) => composed(i).map(r => dis |+| r)
f: (List[Int], Int) => scalaz.\/[String,List[Int]] = <function2>
scala> (1 to 4).toList.foldLeftM[({type l[a] = String \/ a})#l, List[Int]](List[Int]())(f)
!!
res16: scalaz.\/[String,List[Int]] = -\/(error)
Is it possible to do something like the following?
def takeCurriedFnAsArg(f: (Int)(implicit MyClass) => Result)
Yes, it is possible.
When you have the second curried parameter marked as implicit, the function seems to be not of type
Int => (MyClass => Result) => ResultOfFunction
which it would be if the curried higher order function parameter was a regular parameter; instead, it looks like this:
Int => ResultOfFunction
Here's a quick example:
scala> def curriedFn(i : Int)(implicit func : String => Int) : Boolean = (i + func("test!")) % 2 == 0
curriedFn: (i: Int)(implicit func: String => Int)Boolean
scala> implicit val fn : String => Int = s => s.length
fn: String => Int = <function1>
scala> curriedFn _
res4: Int => Boolean = <function1>
As you can see, the implicit parameter got 'eliminated'. Why and how? That's a question for someone more knowledgeable than me. If I had to guess, I'd say the compiler directly substitutes the parameter with the implicit value, but that might very well be false.
Anyway, digressions aside, here's an example very relevant to your situation:
scala> def foo(func : Int => Boolean) = if(func(3)) "True!" else "False!"
foo: (func: Int => Boolean)String
scala> foo(curriedFn)
res2: String = True!
Now if the second function parameter wasn't implicit:
scala> def curriedNonImplicit(i : Int)(fn : String => Int) : Boolean = (i + fn("test!")) % 2 == 0
curriedNonImplicit: (i: Int)(fn: String => Int)Boolean
scala> curriedNonImplicit _
res5: Int => ((String => Int) => Boolean) = <function1>
As you can see, the type of the function is a bit different. That means that the solution will look different too:
scala> def baz(func : Int => (String => Int) => Boolean) = if(func(3)(s => s.length)) "True!" else "False!"
baz: (func: Int => ((String => Int) => Boolean))String
scala> baz(curriedNonImplicit)
res6: String = True!
You have to specify the function directly inside the method, as it wasn't implicitly provided before.
I am wondering if it is possible to use currying on multi parameter-group functions :
scala> def sum(a: Int)(b: Int): Int = { a+b }
sum: (a: Int)(b: Int)Int
scala> sum(3)(4)
res2: Int = 7
scala> val partFunc = sum(3) _
partFunc: Int => Int = <function1>
scala> partFunc(4)
res3: Int = 7
scala> val partFunc2 = sum _ _
<console>:1: error: ';' expected but '_' found.
val partFunc2 = sum _ _
^
scala> val partFunc2 = (sum _) _
<console>:8: error: _ must follow method; cannot follow Int => (Int => Int)
val partFunc2 = (sum _) _
Writing simply sum _ does not yet have anything to do with the arguments of sum, but simply distinguishes the function object sum from an application of the function.
Hence, you can write:
scala> val partFunc2 = sum _
partFunc2: Int => (Int => Int) = <function1>
As you can see from the type information, this is already the curried version of sum which takes two Int parameters.
Of course, you can then proceed as before with partFunc2(4) being of type Int => Int and so on.
You can do it like this:
val partFunc2 = sum _
or like this:
val partFunc2 = sum(3) _
Considering
object A {
def m(i: Int) = i
val m = (i: Int) => i * 2
}
one gets
scala> A.m(2)
<console>: error: ambiguous reference to overloaded definition,
both value m in object A of type => (Int) => Int
and method m in object A of type (i: Int)Int
match argument types (Int)
A.m(2)
^
Accessing the val can be done with
scala> val fun = A.m
fun: (Int) => Int = <function1>
scala> fun(2)
res: Int = 4
or
scala> A.m.apply(2)
res: Int = 4
but how would one access the def?
It is total rubbish (please, don't do this at home), but you can do it by assigning A to a variable of structural type, that has only the first m.
val x : { def m(i:Int):Int } = A
x.m(10)