6 ms·
> However I hope that they provide some very robust tools for controlling input splitting Yes, splitting and combining. Looking at the code example, I feel lik
by nateabele 12y ago
> However I hope that they provide some very robust tools for controlling input splitting
Yes, splitting and combining. Looking at the code example, I feel like so much opportunity is just being squandered, where something like Rust's mapping constructs would feel so much better. Yours is definitely more in that vein, here's something a little closer:
STDIN | /\w+/{|word|
/house/ => "foo"
/car/ => "bar"
"literal" => "baz"
_ => "dib"
# (where _ is a magical symbol for the default case... could be anything)
}
- rudolf0 12y agoStreaming, pattern matching, and regex combined in one sounds pretty damn cool. Might also be nice to borrow some of Scala's features for terser code than Ruby, like ary | { _ + 5 } instead of ary | { |el| el + 5 }
- spoiler 12y agoI prefer {|el| el + 5} more than { _ + 5 } the latter is too implicit for my taste, also I imagine it could become more confusing in a more complex context.
- rudolf0 12y agoPersonally I like it and find it clear. Compare: ary.map(_ * 2) ary.map(x => x * 2) "_" is perhaps an ugly choice of character (frankly I'm not sure why Scala is so obsessed with it, since it's used for so many featurse), but I think the semantics are sensible. Of course, in a more functional language you could perhaps just write ary.map(* 2)
- kbenson 12y agoProbably because underscore is often used by convention in forms and other typography to indicate "something goes here which is to be supplied." In that respect it's no different that Perl's $_ (actually it's the Exact same thing, as the $ in Perl just denotes a variable, so they are both the variable _), or Perl 6's "whatever" which is written as "*".
- Alphasite_ 12y agoWhat about a middle ground on swift's syntax? Arr.map { $1 * 2 }
- ryanlschneider 12y agoThat was going to be my suggestion too. With the added benefit that is supports multiple arguments.
- rudolf0 12y agoYeah, that'd be pretty cool.
- breuleux 12y agoThis is not a confusing context, though. This would be a confusing context: ary.map(f(_ * 2)) ==> ary.map(x => f(x * 2)) ? ==> ary.map(f(x => x * 2)) ? How does Scala interpret that one? I have no idea.
- ssmoot 12y agoIt doesn't. It's invalid code in most (all?) cases. scala> val f: Int => Int = _ - 1 f: Int => Int = <function1> scala> val ary = Array(1,2,3) ary: Array[Int] = Array(1, 2, 3) scala> ary.map(f(_ * 2)) <console>:10: error: missing parameter type for expanded function ((x$1) => x$1.$times(2)) ary.map(f(_ * 2)) ^ You can't think of "_" like a placeholder. It's not. It's to lift an argument of a function. So simplify it: map in this context wants a Function[Int, Int] right? So f(_ * 2) must return a Function[Int,Int]. But it doesn't probably. _ is lifting some argument out of whatever f is. If you assume _ is an Int, does f take a Function[Int,Int]? No. It takes an Int. So there's no way to parse this that makes sense. It's not just "I have a stack of vars, pull one off the stack and bind it every time I write an underscore, reading left to right". That would be some AST generative grammar hack. That's not what the underscore is. It's simpler and more consistent than that. What you're probably looking for instead is Function Composition. So something like: scala> ary.map(f compose(_ * 2)) res10: Array[Int] = Array(1, 3, 5) So why does that work? Because we were able to compose f() into a larger function that satisfies the signature of the argument map[T](Int => T) requires. A lot like a Stream conceptually. (Is it correct to say in this context f() is a Monad? I'm not sure, I need to sit down and grok the category stuff sometime...) Or you can write it the long way (calling f inside a new function). But instead of defining "steps" you'd be creating a new imperative function and driving the stack.
- breuleux 12y agoThat's interesting, but you did not answer my question. I wanted to know how Scala determines where to insert =>. In my example, Scala interprets "ary.map(f(_ * 2))" as "ary.map(f(x => x * 2))" (both of these expressions yield the same error). If it interpreted it the other way, then the expression would work (using your definition of f). Perhaps a better example to use would have been: Array((_:Int) * 2) ==> (x:Int) => Array(x * 2) ? (correctly typed) ==> Array((x:Int) => x * 2) ? (also correctly typed) As it turns out, Scala goes for the latter. After playing with the feature a bit I'd say the rules are engineered to fit particular use cases, but they can be a bit finicky if you venture outside of them. For instance, "1 + _ * 2" will work, but "(1 + _) * 2" won't. "f(_)(x)" does not mean the same thing as "(f(_))(x)". I mean, I wouldn't say the feature is bad, but it definitely has a DWIM vibe to it that would make me classify it as a hack.
- ssmoot 12y ago> I'm not sure why Scala is so obsessed with it, since it's used for so many featurse You might check out http://stackoverflow.com/a/8001065/3614122 http://stackoverflow.com/a/8001065/3614122. The interesting thing (to me) is that the majority of those are actually the same feature (lifting functions). It's just such a powerful/flexible one that it's often misinterpreted as an entirely new thing in different contexts. ary.map(_ * 2) Is no different than: val f = (_:Int) * 2 ary.map(f) Or: val f: Int => Int = _ * 2 ary.map(f) You're just using type-inference in conjunction with lifting. I wrote a blog post on it that's maybe not complete garbage. ;-) http://www.ssmoot.me/scala-s-magical-placeholder http://www.ssmoot.me/scala-s-magical-placeholder Some of the other examples of the underscore are pattern-matches, which can be used on the LHS of assignment, similar to Erlang. Which comes in handy writing unit-tests. i.e.: If I expect something to return Some[User], and I'm writing a GET->UPDATE integration test, then I'd probably do something like: "Update should not blow up" in async { val Some(user) = await(db.get(userId)) val update = user.copy(name = "bob") val Success(result) = await(db.put(update)) } Extractors/Pattern-Matching is way way up there for me. Much more significant than for-comprehensions. Though you could write the same code like: "Update should not blow up with a for-comprehension" in { val test = for { Some(user) <- db.get(userId) update = user.copy(name = "bob") Success(result) <- db.put(update) } yield result whenReady(result) { "whatever" } }
- msie 12y agoFor only several characters more the second form is much clearer to many more programmers. I think it's worth it.
- desdiv 12y agoOf course, in a more functional language you could perhaps just write "ary.map( * 2)" Wait, isn't that already possible in Scala? ary.map(2*)
- breuleux 12y agoPersonally I would go for something more like this: STDIN | /\w+/ | {|each match| /house/ => "foo" /car/ => "bar" "literal" => "baz" _ => "dib" } Where "each x" in a parameter list wraps the body in a map and uses x as the loop variable, and "match" in a parameter list instructs that this is the parameter we are doing pattern matching on in the body (no need to name it). I think this is a more flexible solution, and more modifiers than each could be introduced. For instance, sum of squares could be: seq(100) | {|each x| x * x} | {|reduce (x = 0, y)| x + y}