Hacker News new | comments | show | ask | jobs | submit login
Scala One Liners (solog.co)
71 points by DanielRibeiro 2215 days ago | hide | past | web | 35 comments | favorite



Quick little transliteration to ruby:

  1. (1 to 10) map { _ * 2 }
     1.upto(10).map { |x| x * 2 }

  2. (1 to 1000).reduceLeft( _ + _ )
     1.upto(1000).inject { |a, x| a + x }

  3. val wordlist = List("scala", "akka", "play framework", "sbt", "typesafe")
     wordlist = ["scala", "akka", "play framework", "sbt", "typesafe"]
     val tweet = "This is an example tweet talking about scala and sbt."
     tweet = "This is an example tweet talking about scala and sbt"
     (words.foldLeft(false)( _ || tweet.contains(_) ))
     wordlist.any? { |w| tweet[w] }

  4. val FileText = io.Source.fromFile("data.txt").mkString
     file_text = File.read 'data.txt'
     val fileLines = io.Source.fromFile("data.txt").getLines.toList
     file_lines = File.read('data.txt').lines
     Or, more typically,
     File.open('data.txt').each { |line| ... }

   5. (1 to 4).map { i => "Happy Birthday " + (if (i == 3) "dear NAME" else "to You") }.foreach { println }
       4.times { |i| puts "Happy Birthday #{i == 2 ? "dear NAME" : "to You"}" }

   6. val (passed, failed) = List(49, 58, 76, 82, 88, 90) partition ( _ > 60 )
      passed, failed = [49, 58, 76, 82, 88, 90].partition { |x| x > 60 }

   7. val results = XML.load("http://search.twitter.com/search.atom?&q=scala")
      results = Nokogiri::XML open 'http://search.twitter.com/search.atom?&q=scala'

   8. List(14, 35, -7, 46, 98).reduceLeft ( _ min _ )
      [14, 35, -7, 46, 98].min
      [14, 35, -7, 46, 98].inject { |m, i| i > m ? i : m }
I'm impressed! Scala's lambda syntax is obviously bar none. The dual _ + _ was especially pleasing, and completely unexpected. The List() construct is also entirely warranted in place of array literals, given Scala's wide variety of collection types. On the other hand, what is this io.Source.fromFile mess? I don't understand the alternating capitalization, or the need for deep namespacing of an incredibly common type.


"bar none" is a little excessive -- Haskell's syntax is probably even cleaner. Compare:

  1. map (*2) [1..10]

  2. sum [1..1000]
     -- sum = foldl (+) 0

  3. any (`isInfixOf` tweet) wordlist

  4. fileText <- readFile "data.txt"
     fileLines <- lines <$> readFile "data.txt"

  5. mapM_ putStrLn . map (\i -> "Happy Birthday " ++ if i == 3 then "dear NAME" else "to You") $ [1..4]

  6. (passed, failed) = partition (>60) [49,58,76,82,88,90]

  7. -- I avoid XML so I don't know what library you'd use here.

  8. minimum [14, 35, -7, 46, 98]
     -- minimum = foldl1 min


"bar none" is a little excessive -- Haskell's syntax is probably even cleaner. Compare

And ditto for Io (http://www.iolanguage.com):

  1.  1 to(10) map(*2)

  2.  1 to(1000) asList sum

  3.  tweet findSeqs( wordlist )

  4.  fileText  := File with("data.txt") open readLines join
      fileLines := File with("data.txt") open readLines


  5.  4 repeat (i, writeln("Happy Birthday " .. if(i == 2, "dear NAME", "to you")))

  6.  list(49, 58, 76, 82, 88, 90) partition(x, x > 60)


  7.  results := SGML URL with("http://search.twitter.com/search.atom?&q=scala") 
        fetch asXML

  8.  list(14, 35, -7, 46, 98) min
      list(14, 35, -7, 46, 98) max
Some notes:

i) For 1 & 2 remember to have `Range` loaded first. ii). OK I cheated on 6 because there is no partition currently in the Io core lib. Here is a "simple" way I did it for the example:

    List partition := method (
    
        returnThis := Object clone do (
            passed := list()
            failed := list()
        )
    
        argSlot := call message argAt(0)
        cond    := call message argAt(1)
    
        self foreach (n,
            newSlot(argSlot asString, n)
            if (doMessage(cond), 
                returnThis passed append(n), 
                returnThis failed append(n))
        )
    
        returnThis
    )


Okay, here it is in Perl, the granddaddy of them all when it comes to implicit variables:

1. map { $_ * 2 } (1..10)

2. reduce { $a + $b } (1..1000)

3. scalar grep { /(scala)|(akka)|(play framework)|(sbt)|(typesafe)/ } "This is an example tweet talking about scala and sbt." # Pow, easy regex syntax!

4. open(my $fh, '<', "data.txt"); $/ = undef; my $text = <$fh>; open(my $fh, '<', "data.txt"); my @lines = <$fh>;

5. map { $_ => "Happy Birthday " . (i == 3 ? "dear NAME" : "to you") } (1..4)

6. @grades = (49, 58, 76, 82, 88, 90); @passed = grep { $_ > 60 } @grades; @failed = grep { $_ < 60 } @grades; # Sort of gross, might also do this: my (@passed, @failed); map { $_ > 60 ? push @passed, $_ : push @failed, $_ } (49, 58, 76, 82, 88, 90);

7. # I'm not even going to try, because XML::Parser is disgusting. I'll just point out that you'd probably have the same amount of verbosity and disgustingness telling Scala (or Ruby) to parse $arbitrary_data_format, so XML being a one-liner really isn't a huge win.

8. min(14, 35, -7, 46, 98) max(14, 35, -7, 46, 98)

Note: reduce(), min(), and max() are in List::Util, but that's in perl5 core, so they count.


> On the other hand, what is this io.Source.fromFile mess? I don't understand the alternating capitalization, or the need for deep namespacing of an incredibly common type

Not at all necessary, just convenient for demos since it saves you an import.

"io" : The package is scala.io (the scala part is already imported by default). Following java, package names are always lower case.

"Source": There is a singleton object in the io package called 'Source'. Again, like java, classes and constants (including singleton objects) are capitalized.

"fromFile": A method on the Source singleton. Methods are camelCase.

In 'real' scala code the line would look like:

		import io.Source
		(...)
		val fileText = Source.fromFile("data.txt").mkString
or, even more concisely

		import io.Source.fromFile
		(...)
		val fileText = fromFile("data.txt").mkString
Since methods are just functions (a first class data type), there's no problem importing methods directly.

(edit: I also note that you didn't include all your imports, such as nokogiri, so it's not entirely a level playing filed)


A different Ruby take on 2. that compares well to the _ + _:

   (1..10).inject(:+)


Oh... oh my. I never realized that higher arity blocks worked with that syntax. Thanks for that one.


looks like I'm late to the party.. I rewrote most of them in CoffeeScript: http://ricardo.cc/2011/06/02/10-CoffeeScript-One-Liners-to-I...

I'm specially fond of

    "Happy Birthday #{if i is 3 then "dear Robert" else "to You"}" for i in [1..4]


It's calling the fromFile method on the io.Source object. Package names are lower-case by convention, class and object names are capitalized camel-case, and methods are lower-case camel-case.

Also, 1.upto(10) can also be written as (1..10) in ruby


By the way, it is possible to have methods and values on the package itself, like math.sin(math.Pi), but that hasn't been done with scala.io.

You can also import singleton methods, so if you write

  import io.Source._
then all the fromX methods are available directly.


There this gem that brings the underscore syntax to Ruby: http://bit.ly/a6QmgL


This post neatly demonstrates some things I don't like about Scala. Background: I've spent thirty or forty hours programming toy projects in Scala. That's not a whole lot, but it's enough that some things should start making sense . . . and they haven't.

    (1 to 10) map { _ * 2 }
    (1 to 1000).reduceLeft( _ + _ )
    List(49, 58, 76, 82, 88, 90) partition ( _ > 60 )
I guess one common syntax for this pattern isn't sufficient. :( To be perfectly clear about my objection, these are the same basic operation: call a function on an iterable with an additional function argument. One is dotfree and uses braces. One uses a dot. And one is dotfree and uses parens. I feel like it would be a lot better if there were only one way to do this.

    (words.foldLeft(false)( _ || tweet.contains(_) ))
|| . . . in every other language that means "logical or". What non-intuitive connotation does it have here?

    val results = XML.load("http://search.twitter.com/search.atom?&q=scala)
Oh man, why can't it be XML.parse(URL.fetch(...)).

    (n: Int) => (2 to n) |> (r => 
        r.foldLeft(r.toSet)((ps, x) => if (ps(x)) ps -- (x * x to n by x) else ps))
This language has a damn operator fetish. This is sort of ok . . . I suppose these operators mean something to someone, but why do they have to also break conventions by doing things like creating a binary --.

Despite these complaints, and many others, I'm still weirdly drawn to this language. I want a smaller version of this. Managed, non-crazy (I'm looking at you, Go), and providing functional features. But I want that in a package that doesn't give me ten million billion different ways to do the same thing.


In Scala '||' does mean logical OR.

The example given is using the logical OR to fold across booleans.

Imagine this expression:

    (a || b || c || d || e || f || g || h)
If any of those values are true, the whole expression evaluates as true. It only evaluates as false if all the values are false.

Now consider a simple example in Scala:

    val res1 = List(false, false, false, false, true)
    res1.foldLeft(false) { _ || _ }
Here the foldLeft function is 'accumulating' the value of the boolean by doing an OR comparison with the starting value (false). For all but the last one, it is doing (false || false -> false), then it hits the last one and does (false || true -> true).

It's a neat trick, and useful if you were using a programming language that had foldLeft but not exists.

In Scala, you have exists. So you can do this instead:

    res1.exists(_ == true)
Or for the example given, something like this:

    words.exists(tweet.contains(_))


Oh, fail me for that particular point. I should have looked at what function was being called rather than just the syntax.


  (words.foldLeft(false)( _ || tweet.contains(_) ))
> || . . . in every other language that means "logical or". What non-intuitive connotation does it have here?

The "non-intuitive connotation" || has here is "logical or". The idea of "foldLeft" is that you are taking the previous value and operating on it to obtain the next value. In this case, you start with "false" (the default assumption: that the string does not contain any of the words) and then check, one by one, whether any of the words are in the tweet: for each word, you || the new result against the previous value.


> One is dotfree and uses braces. One uses a dot. And one is dotfree and uses parens. I feel like it would be a lot better if there were only one way to do this.

I don't disagree with the principal of your complaint, coming from working with Perl I know of the potential horrors of having such flexibility.

But just to explain why you can have both braces and parens here. In Scala, if you have a single parameter to a function, you can use braces. This is to allow you to create your own DSLs and control structures. The standard example is:

    def withPrinter(file: File)(op: PrintWriter => Unit) {
      val writer = new FileWriter(file)
      try {
        op(file)
      } finally {
        writer.close()
      }
    }
Which for these types of blog posts we could call as:

    withWriter(new File("test.txt"))(_.println("test"))

But in real applications where function bodies might be more complex, then you can have control abstractions like this:

    withWriter(new File("test.txt")) {
      writer => writer.println("test")
    }

So used in a tasteful and sensible way, it's a really nice feature.


  val results = XML.load("http://search.twitter.com/search.atom?&q=scala)
> Oh man, why can't it be XML.parse(URL.fetch(...)).

  XML.load(io.Source.fromURL("http://search.twitter.com/search.atom?&q=scala").reader)


Gosu equivalents:

1) (1..10).map( \ i -> i * 2 )

2) (1..1000).sum()

3) words.hasMatch( \ word -> tweet.contains( word ) )

4) var fileText = new File("data.txt").read()

5) (1..4).map( \ i -> "Happy Birthday " + (i == 3 ? "dear Name" : "to You") ).each( \ l -> print( l ) )

6) var map = {49, 58, 76, 82, 88, 90}.partition( \ i -> i > 60 )

Note: partition() in Gosu is not limited to a true/false codomain.

7) var x = XmlElement.parse( new URL("http://www.yahoo.com/) )

8) {14, 35, -7, 46, 98}.min() or {14, 35, -7, 46, 98}.max()

9) No equivalent, there is no parallel stuff built into Gosu as of yet.

10) No equivalent, there is no operator overloading in Gosu.

I agree with the comment above pointing out that all of this is available (or easy to mimic) in most high level languages.

However, I think that the different flavor of Gosu and Scala is apparent from this list: Scala tends towards abstraction, reusing .reduceLeft() and the magic underscores to express things, whereas Gosu has distinct functions for common operations and requires named closure arguments. Our take is that this makes Gosu code easier to understand and maintain but, of course, that is subjective.

It's just that we're right.

;)


Am I supposed to be impressed? Just about all of these are oneliners in most high level programming languages. The test of a languages expressiveness is much bigger programs.


What do you mean by the "test of a languages expressiveness"? (I assume you meant "much bigger problems"?) Could you give us some examples?


Scala oneliners:

  "Multiply a list by 2"
REBOL oneliners (http://www.rebol.com/oneliners.html):

  "Open a GUI, read web page, send it as email"


Factor IIRC:

    1) 10 [1,b] [ 2 * ] map
    2) 1000 [1,b] sum
    3) { "scala" "akka" "play framework" "sbt" "typesafe" }
       "This is an example tweet talking about scala and sbt."
       '[ _ subseq? ] map
    4) "data.txt" utf8 file-lines
    5) 4 [1,b] [ 3 = [ "you" print ] [ "dear" print ] if ] each
    6) { 49 58 76 82 88 90 } [ 60 > ] partition
    7) "http://search.twitter.com/search.atom?&q=scala" http-get string>xml
    8) 100000 sieve :)


Hmm, I wouldn't actually think of Scala to write this demo in (except for its advantageous standard library). Strongly typed languages tend to have some additional boilerplate code that can make them less effective for "code golf"-like contests.

Someone else posted Haskell code (which is what I would have gone for), but I think that all this really shows is that the tasks tended to be optimized for code which lends itself to easy typed high-order functions.


1.

  map (*2) [1..10]
2.

  sum [1..1000]
Haskell, will post all 10 after work unless someone beats me to it.



Can anyone do the examples in Clojure, please?


1)

    (map #(* % 2) (range 1 10))
2)

    (reduce + (range 1 1000))
3)

    (def string "This is an example tweet talking about scala and sbt.")

    (some #(.contains string %) ["scala", "akka", "play framework", "sbt", "typesafe"])
4)

As a string:

    (slurp "filename")
As a list you could just do:

    (.split (slurp "filename") "\n")
Or if you want a lazy sequence:

    (line-seq (BufferedReader. (InputStreamReader. (FileInputStream. file-path) "UTF-8")))
There are also contrib libraries for this that do it nicer.

5)

    (apply prn (map #(str "Happy birthday" (if (= % 4) " dear NAME" " to you")) (range 1 5)))
6) I'm going to leave this blank for now. It's an easy enough problem, but I can't think of a way of doing it in a nifty one-liner.

Edit: Ahh thought of it now. group-by does it nicely:

    (group-by #(> % 60) [49, 58, 76, 82, 88, 90])
which returns a map with the elements keyed to the result of the anonymous function. In this case:

    {false [49 58], true [76 82 88 90]}
7) Something like

    (xml-seq (clojure.xml/parse the-xml))
probably.

8)

    (apply max [14, 35, -7, 46, 98])

    (apply min [14, 35, -7, 46, 98])
9) Clojure has pmap, which is used just like map is, work is just done in parallel. Also Clojure is known for its concurrency features, which I won't go over here.

10) I'm sure this can be done in a similar amount of code in Clojure, though I am not going to try.

Any comments/corrections are welcome.


For Python:

1) Here we note that Python's range() is not RH-inclusive.

  [i * 2 for i in range(1, 11)]
2) Ugh, reduce().

  reduce(operator.add, range(1, 1001))
3) any() is awesome.

  wordlist= ["scala", "akka", "play framework", "sbt", "typesafe"]
  tweet = "This is an example tweet talking about scala and sbt."
  any(word in tweet for word in wordList)
4) These are not very idiomatic in Python, but that's alright.

  fileText = open("data.txt").read()
  fileLines = open("data.txt").readlines()
5) Hm, interesting. To make it print correctly, I used a newline join.

  print "\n".join("Happy Birthday %s" % ("dear NAME" if i == 3 else "to You") for i in range(1, 5))
6) Ah, this is where it becomes apparent that Python is not a functional language. On the other hand, this version doesn't hide the actual expense of list allocation, so I guess it evens out. Can somebody come up with a better answer here?

  passed = []; failed = []; [passed.append(i) if i > 60 else failed.append(i) for i in [49, 58, 76, 82, 88, 90]]
7) Not gonna bother. Use lxml.

8) Oh, this is easy.

  min([14, 35, -7, 46, 98])
  max([14, 35, -7, 46, 98])
9) Entire books have been written on this. Python does have multiprocessing.Pool.map(), though it takes a bit of setup.

10) Whew, this took me a second. You'll want to import some of these from itertools, and it needs to be redefined each time, since lambdas can't really define local stuff easily. On the plus side, it's shorter than the Scala flavor, and relies on standard stuff. :3

  g = lambda l=[2]: ifilter(lambda x: (all(x % i for i in l) and (l.append(x) or True)), count(3))
That was fun!


For 6) itertools.groupby() helps a bit:

  import itertools
  passed, failed = (list(v) for k,v in itertools.groupby([49, 58, 76, 82, 88, 90], lambda x: x > 60))


You could do 6 like so for kicks (it's pretty horrible and writing a real partition function is easy neough):

    passed, failed = reduce(lambda r, g: r[g <= 60].append(g) or r, [49, 58, 76, 82, 88, 90], ([], []))


I often wonder why people would use anything other than Python for doing real work. Such a fantastic language! I admit I am somewhat of a fanboy but I feel like it's for a good reason. The language is so easy to read, like reading a sentence. I cannot recall who said this (I want to say Steve Jobs) but its something on the lines of "something is only perfect when there is nothing left to take away" .. The fact that Python is missing so many of the crazy symbols and reads more like natural language while still being able to do so much gives me reason to believe it's one of tue greatest scripting languages around, and certainly clowns on Scala for these examples. I really wonder why people continue to write web apps in PHP for example.


> I cannot recall who said this (I want to say Steve Jobs)

Antoine de Saint-Exupery. Il semble que la perfection soit atteinte non quand il n'y a plus rien à ajouter, mais quand il n'y a plus rien à retrancher. "It seems that perfection is attained not when there is nothing more to add, but when there is nothing more to remove."

But don't let that stop you say "Steve Jobs" if you happen to enjoy saying it :-).


You should use sum for #2:

  sum(range(1,1001))


oh come on, for #2 you don't want to use sum() ? :)


As others have pointed out, sum() is the right thing for (2), and groupby() could be used to build a real partition for (6). Clearly I should have tried this in the morning, after a full night's sleep. :3 More seriously, for (2), (9), and (10), I was trying to answer with similar one-liners that have the same kind of complexity and results, to show that Python's syntax isn't that scary.

Also, I should note that there is a one-liner for using urllib and lxml to grab and parse an XML file, but there's another one-liner using Twisted to do the same thing; it depends on your context. Why do you want the XML? What are you doing with it? That is something important that needs to be considered.




Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | DMCA | Apply to YC | Contact

Search: