That would mean we incur the list fold's super annoying issue.
scala> def f[T](xs: List[T]) = xs.foldLeft(Nil)((x, y) => x :+ y)
<console>:7: error: type mismatch;
found : List[T]
required: scala.collection.immutable.Nil.type
def f[T](xs: List[T]) = xs.foldLeft(Nil)((x, y) => x :+ y)
^
Same parameter list avoids this.
If you use -optimise these are all inlined and eliminated.
You're right about this though.
> I would caution us against going too far down this road though for generalIf you use -optimise these are all inlined and eliminated.
> ADTs due to the performance implications of building unused thunks for every
> case at every call site.
Your experience probably isn't up to date. I would definitely like to
know of any circumstance where Option#getOrElse is not inlined under
-optimise using current trunk. This will inline with the same
frequency, which AFAIK is 100%.
> In my experience, this works a lot less frequently than one would expect.Your experience probably isn't up to date. I would definitely like to
know of any circumstance where Option#getOrElse is not inlined under
-optimise using current trunk. This will inline with the same
frequency, which AFAIK is 100%.
Either is inconsistent in a million different ways, and does not serve
as effective precedent.
Having just implemented it, I found the ascribing worse in the same
parameter list, for the reason daniel gave. No longer would a
function type be inferred.
I thought about this some. I don't really buy the consistency argument: Either.fold takes a uncurried parameter list.
The type-inference issue that Paul mentions below is the deal breaker for me. Just try this exercise: http://blog.tmorris.net/further-understanding-scalaoption/ with the curried and the uncurried forms and I think you'll agree.
Much of the conciseness gains we achieve with adding fold are lost if we need to add ugly type ascriptions.
I should point out there is clearly a way around it in this case. We
infer an overly specific type in the first parameter list, then fail
the compile in the second parameter list. There's no fundamental
reason we could not backtrack to the first parameter list and infer a
less specific type, at which point everything would work with flying
colors. I'm not saying we should do that (or that we shouldn't) or
that there wouldn't be complications in the general case.
I should point out there is clearly a way around it in this case. We
infer an overly specific type in the first parameter list, then fail
the compile in the second parameter list. There's no fundamental
reason we could not backtrack to the first parameter list and infer a
less specific type, at which point everything would work with flying
colors. I'm not saying we should do that (or that we shouldn't) or
that there wouldn't be complications in the general case.
It doesn't have to turn the dial all the way to Any, nor would it in
any sane scenario. It only has to widen singleton types.
In fact, I wonder if one could annotate fold's signature...
def foldLeft[B](z: B)(op: (B, A) => B)(implicit ev: B !<:< Singleton): B
I invented a syntax for "is not a subtype of" which as far as I know
we can't express directly but can using the create-an-ambiguity trick.
If you can exclude Nil.type from valid inferences for B then I think
it will just work.
xs.foldLeft(Some(42)) { (a, b) => a filter (b ==) }
Obviously facetious example, but you get the idea.
Daniel
Okay, how about widening final types. I understand this is rather ad
hoc, something I am not nearly so allergic to as are some other
people, when I think the circumstances call for it.
xs.foldRight(List(Nil)) { _ :: _ }
Daniel
I don't feel the need to solve the universe's problems when we're
talking about going from "does not compile, despite obvious meaning"
to "does compile, with obvious meaning" for some set of common cases.
That was my point about not being overly allergic to ad hoc measures.
Anyone who thinks we don't already apply heuristics of this kind
should look through the compiler source sometime.
on Option[A]. If we think that the need to sometimes type-annotate the none branch is so awkward that it's better to do without, then maybe it's better to do without. But I tend to think it's probably not that large a problem.
Actually, this order of parameters is correct, but not for the reasons you mention.
While we are at out, let's add Boolean.fold (if/else with the argument order dunrite).
--
Tony Morris
http://tmorris.net/
We have recently adopted the idea of uncurried first, optionally curried
over the top. The reasons are immensely drawn out and bring up
contentions between sound library design, Scala's type inference, JVM
target and more.
Yep, the rationale for parameter grouping in Scalaz 7 goes like:
1. By default, use a single parameter section.
2. Split this into multiple parameter sections if there is a type
inference benefit. (I prefer not to call this 'curried' to avoid
confusion with #3)
3. Avoid currying like: def foo(a: A): B => C => D.
Why?
- #2 compiles to normal method dispatch, #3 involves indirection at
runtime through Function1.
- #1 and #2 allow names on the parameters, which I find easier to
document and use than #3.
I didn't consider the type inference benefit of inferring the *return*
type of the closure argument to Option#fold until it was pointed out
in this thread; until now I've only considered changes to help infer
the *parameter* type.
-jason
Actually, this order of parameters is correct, but not for the reasons you mention.
While we are at out, let's add Boolean.fold (if/else with the argument order dunrite).
This is the problem with if/else:
scala> val x = if (true) 1 else 2
x: Int = 1
scala> val x = 1 + if (true) 1 else 2
<console>:1: error: illegal start of simple expression
--
Daniel C. Sobral
I travel to the future all the time.
val x = true.fold(1)(2)
val x = 1 + true.fold(1)(2)
The point is not verbosity, the point is that I can move it around an
expression at will without worrying about adding parenthesis. Sure, I
could put every if statement inside parenthesis, but does anyone?
On Thu, Apr 5, 2012 at 12:42, Daniel Spiewak <djsp...@gmail.com> wrote:val x = true.fold(1)(2)
> Wouldn't a fold invocation and the associated thunks be more verbose than a
> simple pair of parentheses?
val x = 1 + true.fold(1)(2)
On Thu, Apr 5, 2012 at 11:56 AM, Daniel Sobral wrote:
On Thu, Apr 5, 2012 at 12:42, Daniel Spiewak wrote:val x = true.fold(1)(2)
> Wouldn't a fold invocation and the associated thunks be more verbose than a
> simple pair of parentheses?
val x = 1 + true.fold(1)(2)
The biggest problem with this is that the natural order with fold is (onFalse)(onTrue), while the natural order for if is (onTrue)(onFalse).
I'm fine with having the method, but I think it will be confusing regardless of parameter order if we call it fold.