Can you write beautiful code?

Started by cormullion, October 16, 2011, 02:26:55 PM

Previous topic - Next topic

cormullion

Can you write beautiful code?



http://www.cs.princeton.edu/courses/archive/spr09/cos333/beautiful.html">//http://www.cs.princeton.edu/courses/archive/spr09/cos333/beautiful.html



then



https://plus.google.com/117377434815709898403/posts/HQek48JMJb3">//https://plus.google.com/117377434815709898403/posts/HQek48JMJb3

cormullion

#1
Nobody willing to accept the challenge of writing a version in NewLISP? ... :/

rickyboy

#2
Quote from: "cormullion"https://plus.google.com/117377434815709898403/posts/HQek48JMJb3">//https://plus.google.com/117377434815709898403/posts/HQek48JMJb3

It warms my heart to see Clinton's code there -- all that beautiful functional code, with tail recursive calls. :)



To answer your challenge question, one can write a port of Clinton's solution to newlisp pretty much directly.  It would be equivalently beautiful (syntax- and idea-wise).  You've seen the chucks of code I've submitted before on this board which are written in this style.  I really do believe that the functional style is beautiful and better aesthetically than other imperative styles (using this term loosely, I know).  But I do realize that there are many others on this board who would disagree, and I can discern that I am probably in a small minority here.



Here is an interesting article apropos to the idea of "better aesthetically": http://www.paulgraham.com/taste.html">//http://www.paulgraham.com/taste.html.  Enjoy!  --Ricky
(λx. x x) (λx. x x)

cormullion

#3
I was hoping you'd see this, Rick. I think you probably know more about Clojure and C - I can just about recognise a few  familiar idioms in the Clojure code mentioned - it would be interesting to see the code in newLISP.

rickyboy

#4
OK, here's a newLISP solution which tries to be true to the way it was coded by Clinton (in the link cormullion gave us).



First, there is a function in Clojure called second which works like the newLISP call (xs 1) for the Clojure call (second xs).  The only difference is that second will return nil when given degenerate sequence input, like (second "") or (second "a").


(define (second xs)
  (if (> (length xs) 1) (xs 1)))

You can write it as a macro too, if you think you are going to have big sequences.


(define-macro (second)
  (letex (xs (args 0)) (if (> (length xs) 1) (xs 1))))

Next, Clojure's function some is almost like newLISP's exists except that exists returns the first value in the given sequence for which the predicate is true, whereas some will just return true under the same condition.  (They both return nil when no sequence element survives the predicate.) You can use either in this application.  Personally, I like exists better because you get more info back from the function call. (Yeah, Lutz!)  But, if you want the test output to match Clinton's, use the following definition.


(define (some pred coll) (and (exists pred coll) true))
Now, we are ready for the punchline: the port of Clinton's code to newLISP.


(define (tails coll)
  (map (curry slice coll) (sequence 0 (- (length coll) 1))))

(define (matchstar c regexp text)
  (some (curry matchhere regexp)
        (filter (fn (xs) (or (= c (first xs)) (= "." c) (empty? xs)))
                (tails text))))
(Split, because I don't like the scrollbar. :)
(define (matchhere regexp text)
  (if (empty? regexp) true
      (= "*" (second regexp)) (matchstar (first regexp) (slice regexp 2) text)
      (= "$" regexp) (empty? text)
      (empty? text) false
      (= "." (first regexp)) (matchhere (rest regexp) (rest text))
      (= (first regexp) (first text)) (matchhere (rest regexp) (rest text))))

(define (match* regexp text)
  (if (= "^" (first regexp))
      (matchhere (rest regexp) text)
      (some (curry matchhere regexp) (tails text))))
(λx. x x) (λx. x x)

cormullion

#5
Nice, thanks. That's my homework for tomorrow (getting late here)!



Why macro for big sequences?

rickyboy

#6
Because the call to the macro won't make a copy of the sequence.  So the call and return should be faster and will save some memory.
(λx. x x) (λx. x x)

TedWalther

#7
Quote from: "rickyboy"Because the call to the macro won't make a copy of the sequence.  So the call and return should be faster and will save some memory.


Great.  Now let's benchmark it! :-)  I'm really glad you did this.  I was looking at the clojure code and scratching my head.  So many new idioms to learn.  And seeing this problem posted, reminded me of the threadring problem.
Cavemen in bearskins invaded the ivory towers of Artificial Intelligence.  Nine months later, they left with a baby named newLISP.  The women of the ivory towers wept and wailed.  \"Abomination!\" they cried.

TedWalther

#8
Wow, 20 lines of code in newlisp.  And 5 of those, are just defining functions that exist already on Clojure.  There must be an even more concise version using pure newLISP idioms.
Cavemen in bearskins invaded the ivory towers of Artificial Intelligence.  Nine months later, they left with a baby named newLISP.  The women of the ivory towers wept and wailed.  \"Abomination!\" they cried.

cormullion

#9
And the answer is, yes, you can! Or at least, some people can. It's nice code, functional in all the best ways. (Obviously it's much slower than the built-in regex functions, but if newLISP could be compiled like C and Clojure...)



Thanks Rick!