Hacker News new | past | comments | ask | show | jobs | submit login

I find that both are equally (un)readable. However, for expressions that are that long, I'm inclined to write:

    (setv result (-> (+ 1 3 88) 
                     (/ 2) 
                     (- 8)))



I am not a lisper, but that looks pretty cool. The non-lisp ways of writing that would either require adding parens like GP or writing things like "result /= 2", but that means repeating "result" or whatever variable many times.


This is even better than in-fix notation.


Still being an absolute beginner at lispy syntax, I'll have to ask you the same question though.

While I see the awesomeness in threading macros, I'm usually left pondering a while on where the result actually goes in the next s-expression. How long did it take you to get used to that? Would you prefer someting like `as->` for readability?


I thought it's a simple mnemonic: -> means inserting the form just after the beginning of the next one, while ->> inserts at the end of it.

You most certainly can have explicit variable to thread through expressions, like this:

   (it-> (form1 it) (form2 3 it 4) ...)
where it means "previous expression". I think there's a Clojure library which already implements this. You can use that if you want.


in Clojure this is achieved with `as->`


In Racket we actually have a threading macro with ~>

This:

(- (bytes-ref (string->bytes/utf-8 (symbol->string 'abc)) 1) 2)

Becomes this:

(~> 'abc

    symbol->string

    string->bytes/utf-8

    (bytes-ref 1)

    (- 2))

https://docs.racket-lang.org/threading/index.html


I believe the use of "~>" rather than "->" in Racket was set in #lang rackjure which adds in some of the Clojure syntax to Racket. Also amusing is their explanation:

> For example the threading macros are ~> and ~>> (using ~ instead of -) because Racket already uses -> for contracts. Plus as Danny Yoo pointed out to me, ~ is more "thready".

http://docs.racket-lang.org/rackjure/index.html#%28part._.Ba...

More thready indeed :-p


Emacs 25 has thread-first and thread-last macros in subr-x.el.


Also, I've seen lisps that obviate the need for the outermost parentheses (I think by using significant whitespace). In that case, the above example would have as many parens as the python example (for those who are keeping count).


Indeed, I like that better than either typical prefix or infix nested expressions.

What do you advise in the case the expression tree is a little bit more complex?

For example: (setv result (- (/ (+ 1 3 88) 2) (* 8 (+ 3 2)))


Because the operators all take a list of values it's sometimes convenient to format them like any other long list, with each nested sub-expression on its own line to form a tree:

    (setv result (- (/ (+ 1 3 88)
                       2)
                    (* 8 
                       (+ 3 2)))
Another possibility is to use a (let ...) to give nested values temporary names, like:

    (setv result (let ((first (/ (+ 1 3 88) 2))
                       (second (* 8 (+ 3 2))))
                   (- first second)))
It helps if "first" and "second" have meaningful names like "velocity" or "force" that can describe what they are.


I don't see any clever way to make that more readable. I would have to break it into two subexpressions and then take the difference. i.e.

    (setv e0 (-> (+ 1 3 88) (/ 2)))
    (setv e1 (-> (+ 3 2) (* 8)))
    (setv result (- e0 e1))


BTW doesn't setv support multiple pairs?

    (setv e0 (-> (+ 1 3 88) (/ 2)))
          e1 (-> (+ 3 2) (* 8))
          result (- e0 e1))
like setq and setf in CL.




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: