Regularize syntax for lambdas #4712
Comments
|
Is it really necessary to design a syntax for pure functions? I think we just need to provide a @pure annotation: class pure extends scala.annotation.ClassfileAnnotation
type PureFunction[T] = T@pure
val double: PureFunction[Int => Int] = d => d * 2 |
|
This is nice. The part I'm least convinced of is the Alternatively, we could reclaim
The main downside is that |
|
I think adding the [X] => R type -> term
type [X] => R type -> typeCompared to using different arrow symbols to distinguish between type lambda and Polymorphic function type, using the |
|
Yes, I think one will need the parentheses in
|
I would expect or at least hope that once we have pure functions the majority of function types are pure. So we need the simplest and clearest syntax for them, and that's undoubtedly |
|
|
I actually think it might go the other way around. I would guess that most functions written as explicit lambdas are already pure, so reserving Some empirical support would be helpful for this decision. |
|
A grep over 2.5 million lines of code shows >21.661 hits (of which only a few results appear to be false positives). That's close to 1% of the corpus. A subset of the results can be seen here https://gist.github.com/olafurpg/9349c6fb189c9ecb762504cc488d2b07 the full output is in this zip file arrow.zip The val m = Map.newBuilder[Int, Int]
m += (1 -> 2) // OK
m += ((2, 3)) // Not as nice
m += (1, 2) // ERROR
cmd4.sc:1: type mismatch;
found : Int(1)
required: (Int, Int)
val res4 = m += (1, 2)
^I don't have a alternative suggestion, but please consider leaving |
|
to me, |
|
(Note: the builder example does not apply to dotty, where
Relatedly, what should |
|
|
@olafurpg Note that |
|
@odersky Will there be a term syntax to construct pure functions? I interpreted
as if |
|
@olafurpg I don't think we need |
|
I see. The breakage is indeed smaller then, here's what I found for
I am still concerned about giving |
It looks like you're only considering the parsing, but what about the requirements of people reading code? To know whether When I and @liufengyun tried to use variants of this syntax in a draft, we had no convenient way to write pure functions/methods which were visibly pure, and that's not currently addressed by this proposal. So this isn't worth the disruption IMHO. // either pray:
def pureFunction[X](xs: List[X]) = xs.map(f).map(g) // let's hope that f and g are pure
// or give up methods and pray again:
def pureFunction[X] = (xs: List[X]) => xs.map(f).map(g) // let's hope that f and g are pure
// or give up methods *and* return type inference
def pureFunction[X]: (xs: List[X]) -> List[Z] = xs => xs.map(f).map(g) // finally, a compile error if f or g isn't pure |
|
Our approach to purity is really the dual of what you have in mind: Instead of tracking purity, track the capabilities you have in scope to be impure. If there are none, any code that typechecks is pure. |
|
True, if we want to be able to write something like |
For what it's worth, I personally always define: @showAsInfix type -> [+A,+B] = (A,B)
object -> { def unapply[A,B](ab: (A,B)) = Some(ab) }... which I consider to be glaring omissions from the standard library! This way, I can write code like: def foo[K,V](kv: K -> V) = kv match {
case k -> v => assert(kv == k -> v)
} |
|
@LPTK I have good news for you then: scala/scala#6304 |
That's not the plan. If you write that, it means |
|
Will the following solve the problem?
|
|
The group discussion today led to some support for
for the type-level lambdas. One argument in favor is that |
|
For the following reasons, I am not a fan of the There are infinitely many type of impure functionsFunctional programmers are the target audience for pure functions, yet functional programmers care about the distinctions between types of impurity. For example, functional programmers would like to know merely by looking at a type that a function uses the effect of The use of I realize the "implicit effect system" sketched out in an older PR is intended to address this limitation, and while this is a separate topic, I feel the implicit effect system will not be used by either functional programmers or OO programmers. The functional programmers already have better tools and the Java programmers don't care. Impure functions are better modeled by pure functionsFunctional programmers are the target audience for pure functions, yet functional programmers prefer to model all functions as pure. Pure functions have a tremendous simplifying power on reasoning and testing. If we see a function If we see a function Moreover, pure functions give us strictly more compositional power than a mix of pure and impure functions. For example, if we have If we switch this over to the pure/impure proposal, then a function like Escape hatches will be neededSince many functions are, from the outside, pure functions, even though they use an impure implementation, an escape hatch will be necessary. Precisely, the escape hatch will allow an impure function ( The necessary existence of this escape hatch means that it's possible to arbitrarily pretend that any impure function is pure. In other words, the benefit of This does not mean it is useless, only that it's utility is limited to documentation. If there are impure/pure functions, there should be impure/pure methodsBecause methods can be "converted" to functions, and because methods can call functions, in order for a consistent treatment, a bifurcation between pure/impure functions would require a similar bifurcation between pure/impure methods (otherwise there is no information available as to which type of function a method can be converted into). This will introduce additional complexity and confusion, and lead to the need for additional escape hatches. Many other objections have merit
Other languages similar to Scala do not take this approachSee, for example, OCaml, 1ML, etc. No impure functional programming languages take this approach, and the pure ones all take different approaches to effects. In summary, I'd argue the proposal has a large amount of cognitive and pedagogical overhead, introduces a lot of additional complexity into an already complex language, and will not pay for itself given all the limitations mentioned above. It feels like it could facilitate the implicit effect system, but I don't think that will be used by functional programmers or Java programmers. I feel like a simpler proposal would be better: perhaps allow an |
|
@jdegoes I did not understand what you were trying to say until I got to your very last paragraph, which made for a frustrating read. So to spare other people the frustration, what you want is (correct me if I'm wrong): to make 'pure' the default. This would mean leaving everything as it is, except for forcing the effectful to declare themselves You use a confrontational tone while pushing for this, but I am not sure this is even controversial. Leaving syntax considerations aside, I think the goal for everyone here is the same: to require purity by default, and to only allow impure code through explicit mechanisms – be it requiring special imports, adding a capability system, using type classes... you name it! Crucially, these are not mutually exclusive approaches. Different people working in different domains with different skill sets have different needs. Martin and many others think the Haskell way is not always best, let alone always appropriate, so they are trying to implement a system to make the life of those who chose not to use it better. It seems clear that you are not in this category, so why do you even care that much? Again, both camps want purity by default and making impurity explicit, but it's not like they have to agree on a single "one true way" of dealing with impure code. AFAIK the approaches could even be mixed, for great benefits.
What are you trying to say here? You want to be able to say that things are pure, and that's what we want to give you. Where is the problem?
Scala has always had I'm not even sure what you think could be an alternative here. Remove
Huh? OCaml's approach is exactly the status quo currently shared by Scala. I don't see how that comparison brings in any new insights. Also, 1ML is not even a real programming language – it's a research prototype and it's not clear whether what they do for effects makes sense in the context of Scala. |
What about Multicore Ocaml with its algebraic effects? |
|
The syntax of lambdas has been stable for a while so I'll close this, further discussion can go to discourse as usual. |
In light of #4672 it's time to think of a systematic syntax solution for the various kinds of types for lambdas. So far we have:
We'd like to reserve
->for pure functions. This means we are currently lacking a good syntax for polymorphic functions (type -> term). And if we ever would like to introduce dependent functions from terms to types, we are also blocked. In light of this I think it makes sense to revise the syntax of type lambdas to be[X]R. If we do that, we'd have accounted for:The text was updated successfully, but these errors were encountered: