4 ms·
Hey Dr Barski. I'm actually reading your book right now. I do have a question. How do you write Lisp effectively? And by that I mean, Lisp seems to be written f
by Riverheart 8y ago
Hey Dr Barski. I'm actually reading your book right now. I do have a question. How do you write Lisp effectively? And by that I mean, Lisp seems to be written from the inside out due to the nested lists. Is there something that makes it more natural to write:
(trim-string (get-string '(some data)))
Or do you need to know that you're going to call trim before you get the string? Hope that makes sense.
- emsimot 8y agoDoes Common Lisp have something similar to Clojure's threading macros? (trim-string (get-string '(some data))) (-> '(some data) get-string trim-string https://clojure.org/guides/threading_macros https://clojure.org/guides/threading_macros
- pcr910303 8y agoYes, of course there is... Lisp always has the thing you find :-) https://github.com/hipeta/arrow-macros https://github.com/hipeta/arrow-macros
- Riverheart 8y agoThanks guys, that macro makes it easier to see the flow :)
- lispm 8y agohow do you write it in other languages? sin(cos(10.4)); or v = 10.4; c = cos(v); s = sin(c); in Lisp one might write: (let* ((v 10.4) (c (cos v))) (sin c)) really old style: (prog (v c s) (setq v 10.4) (setq c (cos v)) (setq s (sin c)) s)
- __rompy 8y agoWhy not write it as in lisp as: (sin (cos 10.4))
- lispm 8y agoThe question was for alternatives to code that reads inside->out. I personally don't have a problem with it, but I can see that many languages have a more procedural/imperative top->down control flow by default. A Java programmer might prefer that, where a Lisp programmer will be trained to alternate while reading between inside->out and outside-in in code.
- ngcc_hk 8y agoStill using those long expression is unfair A(b(c)) are 2 function calls. Hence (A (b c)) is the fair abd equal expression. And you inside out whilst valid and in fact easier to read (as more normal) would need precedence rule in other scenario. But those examples just not right.
- Riverheart 8y agoThanks for the reply! I'd go the first route unless method chaining was available. SomeData.ToString().Trim() I would like to write idiomatic Lisp code and it's getting easier to read the nested expressions but it breaks the flow to leave the expression and wrap it. Another user mentioned using a command with Emacs to escape the expression and auto wrap it. That might be what I'm looking for.
- kazinator 8y agoThis is the TXR Lisp interactive listener of TXR 215. Quit with :quit or Ctrl-D on empty line. Ctrl-X ? for cheatsheet. 1> [chain tostring trim-str] #<intrinsic fun: 0 param + variadic> 2> [*1 3.4] "3.4" 3> [[chain tostring trim-str] 3.4] "3.4" No ready example of a datatype that requires trimming after a string conversion! We'd have to write one: 4> (defstruct foo nil (:method print (me stream pretty-p) (put-string "foo " stream))) #<struct-type foo> 5> (tostring (new foo)) "foo " Okay we are in business: 6> [[chain tostring trim-str] (new foo)] "foo" Method chaining syntax is possible, but with actual methods only. Most library functions aren't methods; you have to roll your own: 1> (defstruct accum nil (val 0) (:method inc (me : (delta 1)) (inc me.val delta) me) (:method mul (me : (factor 2)) (upd me.val (* factor)) me)) #<struct-type accum> 2> (new accum).(inc).(inc).(mul 3) #S(accum val 6) 3> (new accum).(inc).(inc).(mul 3).val 6 Support for idiom isn't the result of a conscious design decision; it just arises naturally when you have this sort of postfix syntax. TXR's dot syntax is a very straightforward sugar for Lisp structure. Basically x.y.z == (qref x y z). Whitespace is not allowed around the dot. Numbers are also not allowed: 3.4 is a floating-point constant and a.3 or 3.a are invalid. If the leading element is missing, then it's the uref (unbound ref) operator: .y.z == (uref y z). This compiles to a function resembling (lambda (obj) obj.y.z).
- lispm 8y agoThat's the same as: (chain somedata (tostring) (trim)) It's a macro away in Lisp. But I would not use it much, since it kind of defeats the advantage of using nested expressions -> they are actually nested.
- didibus 8y agoThe way I do it, is that in my editor, I can type: '(some data|) Where | is my cursor. And then I have a keybinding that moves my cursor to the front and wraps around like so: (| '(some data)) So I can type the next thing: (get-string| '(some data)) Press it again: (| (get-string '(some-data))) And so on. That way, even though the code is visually nested, I can write it in logical order from what eval first to what eval last. A good editor for editing lisp code makes that possible, as I showed, and many other operations. Basically, get yourself accustomed to a good Lisp editor such as Emacs and I'm sure you'll find that problem will disappear. For me, it's even more productive now typing wise, because I can make more structural edits to my code, which is way faster.
- Riverheart 8y agoFor anyone stubborn enough to want to do this with Vim, I've come up with this. function NestExpression() " Get end paren pos " Returns [0, 0] if not in parens. let save_cursor = getpos('.') " If line not set to zero, append let end_paren_pos = searchpairpos('(', '', ')') if end_paren_pos[0] > 0 execute "normal! a)" else " We're not in a set of parentheses return endif " Return to the inside of the parentheses call setpos('.', save_cursor) " If line not set to zero, start insert " mode, prepend and move cursor left let end_paren_pos = searchpairpos('(', '', ')', 'b') if end_paren_pos[0] > 0 call feedkeys("i( \<LEFT>") endif endfunction nmap fj :call NestExpression()<cr>
- oblio 8y agoI don't think he's talking about how to type the characters... He's probably asking: you're inverting, visually, the order of operations. When does start becoming natural?
- Riverheart 8y agoThis is just what I've been looking for! I've been searching for this and see there are commands for navigating s expressions but I haven't found this example. Is this a built-in command? Is there name for this action?