These thoughts are only half-formed, but I'm posting to the lounge to
help clarify my own thinking. I'm sure that others have already investigated this much more deeply and can point out all the holes! A simple code example should explain the current situation: val f1 : (Int, Int) => Int = (a, b) => a + b val pair : (Int, Int) = (2, 2) f1(2, 2) // = 4 // f1(pair) // won't compile val f2 : ((Int, Int)) => Int = t => { val (a, b) = t; a + b } f2(2, 2) // = 4 f2(pair) // = 4 val f3 : (=> Int, => Int) => Int = { (a, b) => a + b } f3(2, 2) // = 4 // won't compile //val f4 : ((=> Int, => Int)) => Int = t => { val (a, b) = t; a + b } //val pair2 : (=> Int, => Int) = (2, 2) val f5 : (Int*) => Int = seq => seq.reduceLeft[Int](_ + _) f5(2, 2) // = 4 // Surprisingly this compiles val f6 : ((Int*)) => Int = seq => seq.reduceLeft[Int](_ + _) f6(2, 2) // = 4 // but this doesn't of course // val pair3 : (Int*) = (2, 2) So _if_ it was possible to add a more general CBN type '=> T' and allow a repeated final element to a Tuple type '(... , T*)' then _perhaps_ a function type could be more simply defined as A => B. Any other thoughts? Regards, Andrew Foggin |
I don't think the current situation is all that bad, but I'll play. :)
On Nov 14, 2007 11:21 PM, Andrew Foggin <[hidden email]> wrote: > // won't compile > //val f4 : ((=> Int, => Int)) => Int = t => { val (a, b) = t; a + b } > //val pair2 : (=> Int, => Int) = (2, 2) This can get closer if the types are more explicit: def f4b(x:Tuple2[Function0[Int],Function0[Int]]):Int={val (a,b)=x; a()*b()} val f4c:((Tuple2[Function0[Int],Function0[Int]])=>Int) = x => {val (a,b)=x; a()*b()} val f4d: ((()=>Int,()=>Int))=>Int = x => {val (a,b)=x; a()*b()} def toTwo()=2 f4c(toTwo,toTwo) // =4 f4c((toTwo,toTwo)) //=4 val pair3:(()=>Int,()=>Int)=(toTwo,toTwo) p4c(pair3) //=4 // f4c((2,2)) // found : Int(2) required: () => Int // if we add this implicit, more things work implicit def delay[T](t:T)=new Function0[T]{def apply()=t} f4c(2,2) //=4 f4c((2,2)) //=4 val pair2 : (()=> Int,() => Int) = (2,2) f4c(pair2) //=4 val pair =(2,2) // f4c(pair) // found : (Int, Int), required: (() => Int, () => Int) So, if the function takes tuples, fixed length parameters work. Unfortunately, requiring tuples is awkward, nonstandard and inefficent---- unmashalling tuples into parameter lists is the more interesting direction. Implicit untupling doesn't work transparently: val add:(Int,Int)=>Int = _+_; add(2,3) //5 implicit def Untuple[A,B,C](f:Function2[A,B,C])=new Function1[Tuple2[A,B],C] { def apply(x:Tuple2[A,B]):C={val (a:A,b:B)=x;f(a,b)}} // type pattern is unchecked since it is eliminated by erasure add apply ((2,3)) //5, conversion works here // but not here: // add ((2,3)) // wrong number of arguments It's not to hard to wrap functions by hand: case class F2[A,B,C](f:Function2[A,B,C]) extends Function2[A,B,C] with Function1[Tuple2[A,B],C] { def apply(a:A,b:B)=f(a,b); def apply(t:Tuple2[A,B])={val (a:A,b:B)=t;f(a,b)}} // still unchecked val add2=F2(add) val mul2=F2[Int,Int,Int](_*_) mul2((3,4)) mul2(6,7) //42 Other cases could be written for other Function lengths and an overloaded method could construct them all; I don't see how to extend that from functions to methods. > So _if_ it was possible to add a more general CBN type '=> T' and allow > a repeated final element to a Tuple type '(... , T*)' then _perhaps_ a > function type could be more simply defined as A => B. A function where all the elements are the same type is an unusually simple case. -Henry |
Henry Ware wrote:
> I don't think the current situation is all that bad, but I'll play. :) > > I also don't think the current situation is that bad, I just think there is scope for simplification. Anyway, thanks for playing :) > > So, if the function takes tuples, fixed length parameters work. > Unfortunately, requiring tuples is awkward, nonstandard and > inefficent---- unmashalling tuples into parameter lists is the more > interesting direction. > > Agreed! > > It's not to hard to wrap functions by hand: > > case class F2[A,B,C](f:Function2[A,B,C]) extends Function2[A,B,C] with > Function1[Tuple2[A,B],C] { > def apply(a:A,b:B)=f(a,b); > def apply(t:Tuple2[A,B])={val (a:A,b:B)=t;f(a,b)}} // still unchecked > > val add2=F2(add) > val mul2=F2[Int,Int,Int](_*_) > > mul2((3,4)) > mul2(6,7) //42 > > Other cases could be written for other Function lengths and an > overloaded method could construct them all; > I don't see how to extend that from functions to methods. > > parameters could be unified, there would be no more Function2, Function3 etc. - just Function1. The compiler can translate a Function that takes a Tuple to a method with multiple parameters. >> So _if_ it was possible to add a more general CBN type '=> T' and allow >> a repeated final element to a Tuple type '(... , T*)' then _perhaps_ a >> function type could be more simply defined as A => B. >> > > A function where all the elements are the same type is an unusually simple case. > > -Henry > > explained it better by saying that if it were possible to define a tuple like this : (=> S, T, U*) then the parameter list for any function could be replaced by a tuple. As I said at the start, I'm sure there are holes, I just don't see them yet! -Andrew |
On Fri, 2007-11-16 at 15:17 +0900, Andrew Foggin wrote: > > I don't see how to extend that from functions to methods. > > > > > I'd expect methods to stay as they are. But if tuples and function > parameters could be unified, there would be no more Function2, Function3 > etc. - just Function1. What is the difference between function and methods, and why? > Well that would be a Seq[T], not a Tuple. Perhaps I could have > explained it better by saying that if it were possible to define a tuple > like this : (=> S, T, U*) then the parameter list for any function could > be replaced by a tuple. As I said at the start, I'm sure there are > holes, I just don't see them yet! I've been thinking that varargs generics would be nice many times. But would it be useful for anything except tuples? Regards, John |
In reply to this post by Andrew.Foggin
OK. Here's my proposal in more detail:
1. Generalise the '=> T' syntax sugar, so: val a : => Int = 1 + 2 val b: Int = a would desugar to: val a : () => Int = { () => 1 + 2 } val b: Int = a() 2. Extend the varargs syntax sugar to tuples, so: val c : (String, Int*) = ("abc", 1, 2, 3) would desugar to: val c : (String, Seq[Int]) = ("abc", Array(1, 2, 3)) 3. Equate Function{n}[A1, ... A{n}, R] to Function[Tuple{n}[A1, ... A{n}], R]. The underlying implementation would stay the same, so: val f : (Int, Int) => Int = ... still compiles to an anonymous class that in Java would look something like: class ... { ... public int apply(int arg0, int arg1) { ... } } Does this make sense? -Andrew Andrew Foggin wrote: > These thoughts are only half-formed, but I'm posting to the lounge to > help clarify my own thinking. I'm sure that others have already > investigated this much more deeply and can point out all the holes! > > A simple code example should explain the current situation: > > val f1 : (Int, Int) => Int = (a, b) => a + b > val pair : (Int, Int) = (2, 2) > > f1(2, 2) // = 4 > // f1(pair) // won't compile > > val f2 : ((Int, Int)) => Int = t => { val (a, b) = t; a + b } > > f2(2, 2) // = 4 > f2(pair) // = 4 > > val f3 : (=> Int, => Int) => Int = { (a, b) => a + b } > > f3(2, 2) // = 4 > > // won't compile > //val f4 : ((=> Int, => Int)) => Int = t => { val (a, b) = t; a + b } > //val pair2 : (=> Int, => Int) = (2, 2) > > val f5 : (Int*) => Int = seq => seq.reduceLeft[Int](_ + _) > > f5(2, 2) // = 4 > > // Surprisingly this compiles > val f6 : ((Int*)) => Int = seq => seq.reduceLeft[Int](_ + _) > > f6(2, 2) // = 4 > > // but this doesn't of course > // val pair3 : (Int*) = (2, 2) > > So _if_ it was possible to add a more general CBN type '=> T' and > allow a repeated final element to a Tuple type '(... , T*)' then > _perhaps_ a function type could be more simply defined as A => B. > > Any other thoughts? > > Regards, > > Andrew Foggin > |
In reply to this post by John Nilsson
John Nilsson wrote:
> On Fri, 2007-11-16 at 15:17 +0900, Andrew Foggin wrote: > >>> I don't see how to extend that from functions to methods. >>> >>> >>> >> I'd expect methods to stay as they are. But if tuples and function >> parameters could be unified, there would be no more Function2, Function3 >> etc. - just Function1. >> > What is the difference between function and methods, and why? > > probably best explained in the Scala Language Specification where you'll find function types described in section 3.2 (Value Types) and method types described in section 3.3 (Non-Value Types). Briefly, an unapplied or partially-applied method can be viewed as a function value, while a function value can be thought of as an instance of a class with an 'apply' method, which is how functions are implemented behind-the-scenes. But I think you know that, so I suspect I'm not really answering the question you asked :-) BTW I really like this article: http://james-iry.blogspot.com/2007/08/kingdom-of-nerbs.html >> Well that would be a Seq[T], not a Tuple. Perhaps I could have >> explained it better by saying that if it were possible to define a tuple >> like this : (=> S, T, U*) then the parameter list for any function could >> be replaced by a tuple. As I said at the start, I'm sure there are >> holes, I just don't see them yet! >> > > I've been thinking that varargs generics would be nice many times. But > would it be useful for anything except tuples? > > Regards, > John > > beyond tuples, but that's probably my lack of imagination! -Andrew |
On Sun, 2007-11-18 at 13:20 +0900, Andrew Foggin wrote: > IIUC functions and methods are quite different in Scala. This is > probably best explained in the Scala Language Specification where > you'll > find function types described in section 3.2 (Value Types) and method > types described in section 3.3 (Non-Value Types). The spec says: "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 (§6.25)." So for all I can see the special status of methods has no consequences on the programmer that the compiler couldn't hide. Am I wrong? Regards, John |
On 2007-11-18 12:41:20 John Nilsson wrote:
> > On Sun, 2007-11-18 at 13:20 +0900, Andrew Foggin wrote: > > IIUC functions and methods are quite different in Scala. This is > > probably best explained in the Scala Language Specification where > > you'll > > find function types described in section 3.2 (Value Types) and > > method types described in section 3.3 (Non-Value Types). > > The spec says: > > "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 (§6.25)." > > So for all I can see the special status of methods has no consequences > on the programmer that the compiler couldn't hide. > > Am I wrong? Yes. A function (closure) is an object. A method is a member of a class (i.e. is not a first-class value). One cannot define methods in terms of functions not least because functions have methods. The most notable of those is 'apply'. Classes and methods are primitive language concepts. Functions are not. They are just instances of the FunctionN classes in the standard library. This also implies that functions cannot be polymorphic and cannot be overloaded. /J |
On Sun, 2007-11-18 at 12:03 +0000, Jamie Webb wrote: > On 2007-11-18 12:41:20 John Nilsson wrote: > > > > On Sun, 2007-11-18 at 13:20 +0900, Andrew Foggin wrote: > > > IIUC functions and methods are quite different in Scala. This is > > > probably best explained in the Scala Language Specification where > > > you'll > > > find function types described in section 3.2 (Value Types) and > > > method types described in section 3.3 (Non-Value Types). > > > > The spec says: > > > > "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 (§6.25)." > > > > So for all I can see the special status of methods has no consequences > > on the programmer that the compiler couldn't hide. > > > > Am I wrong? > > Yes. A function (closure) is an object. A method is a member of a > class (i.e. is not a first-class value). One cannot define methods in > terms of functions not least because functions have methods. The most > notable of those is 'apply'. > > Classes and methods are primitive language concepts. Functions are not. > They are just instances of the FunctionN classes in the standard > library. This also implies that functions cannot be polymorphic and > cannot be overloaded. > > /J Thanks you for that. I can see how that can be problematic given the current design. I could imagine an approach where apply() was implemented as some other type though. Something more primitive than function, Seq[Stmt] or other representation of executable construct f.ex. But that is an entirely different language :P Regards, John |
In reply to this post by Andrew.Foggin
On 18 Nov 2007, at 05:20, Andrew Foggin wrote: >> I've been thinking that varargs generics would be nice many times. >> But >> would it be useful for anything except tuples? >> >> Regards, >> John >> >> > That would be enough for me. I can't see how you would declare/use > this beyond tuples, but that's probably my lack of imagination! Omega (http://web.cecs.pdx.edu/~sheard/papers/SumSchNotes.ps) I posted about this a while ago: http://article.gmane.org/ gmane.comp.lang.scala.user/595 (generalising tuples to records) In the meantime, I've been experimenting with tuples as well: http://kinded-scala.googlecode.com/svn/trunk/examples/src/scala/ examples/tcpoly/typecomp/tuples/tuples.scala I hope to write a short article about this by year's end. adriaan |
Powered by Nabble | Edit this page |