11 ms·
I keep hearing this kind of talk about lisp. I've never actually written anything in it, but if you asked me why, it would have nothing to do with parens or syn
by Retra 9y ago
I keep hearing this kind of talk about lisp. I've never actually written anything in it, but if you asked me why, it would have nothing to do with parens or syntax. It has everything to do with the fact that, for most purposes, Python suits me just fine, and for almost all other purposes, I want a language that compiles to machine code.
Lisps just don't bring much to the table. Their dynamic-ness brings overhead that is not justified unless you're doing crazy macro stuff, and ad-hoc crazy macro stuff is not easy to put into code without hurting readability and comprehension.
- omaranto 9y agoPlenty of implementations of dialects of Lisp have compilers that produce machine code. I would even say that for Common Lisp implementations it is more common to have a compiler than to not have one. There are several great Scheme compilers too, and Racket has a JIT. Here's a sample session with SBCL, where I define a function, which is immediately compiled, and then I request a disassembly: CL-USER> (defun foo (n m) (* (1+ m) n)) FOO CL-USER> (disassemble #'foo) ; disassembly for FOO ; Size: 48 bytes. Origin: #x1007CED6F3 ; 6F3: 498B4C2460 MOV RCX, [R12+96] ; thread.binding-stack-pointer ; no-arg-parsing entry point ; 6F8: 48894DF8 MOV [RBP-8], RCX ; 6FC: 488B55E8 MOV RDX, [RBP-24] ; 700: BF02000000 MOV EDI, 2 ; 705: 41BBC0010020 MOV R11D, 536871360 ; GENERIC-+ ; 70B: 41FFD3 CALL R11 ; 70E: 488B7DF0 MOV RDI, [RBP-16] ; 712: 41BBA0020020 MOV R11D, 536871584 ; GENERIC-* ; 718: 41FFD3 CALL R11 ; 71B: 488BE5 MOV RSP, RBP ; 71E: F8 CLC ; 71F: 5D POP RBP ; 720: C3 RET ; 721: CC10 BREAK 16 ; Invalid argument count trap
- white-flame 9y agoAnd if you declare types in SBCL as fixnum (register-sized ints): CL-USER> (disassemble #'foo) ; disassembly for FOO ; Size: 19 bytes. Origin: #x100784BCCB ; CB: 48FFC0 INC RAX ; no-arg-parsing entry point ; CE: 480FAFC1 IMUL RAX, RCX ; D2: 48D1E0 SHL RAX, 1 ; D5: 488BD0 MOV RDX, RAX ; D8: 488BE5 MOV RSP, RBP ; DB: F8 CLC ; DC: 5D POP RBP ; DD: C3 RET As far as overhead goes, the SHL makes room for tag bits (and notice that's only done once, not per math op), and CLC indicates that the function doesn't return multiple values. That is not significant overhead, and will absolutely destroy reference Python in speed.
- omaranto 9y agoMaybe it's worth pointing out that to get that code like that from SBCL it's not enough to declare that m and n are fixnums, you also need to promise the compiler that the multiplication won't overflow: (defun foo (n m) (declare (type fixnum m n) (optimize (safety 0))) (the fixnum (* (1+ m) n)))
- white-flame 9y agoThe reason I didn't list it is because there's so many different ways to do it. The optimization declaration can be made globally, or per-file; declaring the type of the foo function (including parameters & return values) externally will fully cover this function without having anything additional in the body; there's helper macros to explicitly manage static types, etc. So the type declarations don't need to be intrusive into the expressions themselves, and can be as transparent as you want. Of course, type inference also means that you don't have to specify every single type, while still getting the speed & checking benefit of fully typed code.
- omaranto 9y agoCould you show a way to get that code to be generated without any declarations in the body of the function? I tried something like: (declaim (ftype (function (fixnum fixnum) fixnum) foo) (optimize (safety 0))) (defun foo (m n) (* (1+ m) n)) That didn't optimize as fully.
- white-flame 9y agoYou forgot (optimize (speed 3))
- omaranto 9y agoI did try with speed 3. Do you mean that: (declaim (ftype (function (fixnum fixnum) fixnum) foo) (optimize (safety 0) (speed 3)) (defun foo (m n) (* (1+ m) n)) should have produced the optimized code (without any generic-*)? It didn't in my testing on SBCL 1.3.18.
- jasonkostempski 9y agoThe syntax actually enticed me to play with lisp, and I do like it a lot, but I never found strong reason to prefer using, say, Common Lisp over a more mainstream language/framework stack. I'm just starting to dig into Clojure and I think the combination of lisp syntax and strong support for, and encouragement towards, immutable data really brings a lot to the table in both reason-ability and efficiency.
- white-flame 9y ago> Their dynamic-ness brings overhead that is not justified unless you're doing crazy macro stuff, and ad-hoc crazy macro stuff is not easy to put into code without hurting readability and comprehension. I think that is today's major barrier to Lisp, but not in the way you think. Most of Lisp's inventive features have crept into other languages by now, except for the in-language compile-time code transformation/generation (ie macros & homoiconicity). The major phrase I want to point out is "crazy macro stuff". To people from other programming languages, code generation and metaprogramming are way out there concepts, only suitable for insane scenarios. People said the same thing about functional programming, yet any well-seasoned programmer today has a reasonable handle on its usefulness and advantages, and FP style is now used by programmers in many languages to contain complexity. Lisp-style macro programming is a simple way to do metaprogramming, while in other languages it's an impedance-mismatch-riddled nightmare of separate wonky build steps. Once it is made simple, it's easy to add great conveniences, compile-time optimizations, and architectural support to your programming, with almost no-brainer effort. It is also much easier to human-parse Lisp code which utilizes a good per-project macro library, than it is to parse other languages with boilerplate and sprawling behavioral dependencies injected all over their usage scenarios. The catch-22 is that this style of super-easy metaprogramming is linked to code-is-data-is-code homoiconicity, and people still reject that at face value, which slows the propagation of metaprogramming (however, I think there is a continually slow-rising acceptance). Functional programming doesn't require any unique syntax, just semantics, so it was able to spread without that barrier.
- kazinator 9y agoLisp has been compiled since 1960. Every major Common Lisp implementation is compiled, and some are only compiled; as in, every darn thing you type into the REPL, including (+ 2 2) is converted to native machine code and then branched to: there is no interpreter and hence the eval function compiles, too. That kind of thing was done long before "JIT" was a buzzword. Macros make a tremendous contribution to readability and comprehension. I'm informed by 17 years of Lisp experience versus your zero.
- Retra 9y agoI'm only saying why I haven't learned Lisp, which seems perfectly well due to misunderstandings. So cut it with the shitty attitude.
- pjmlp 9y agoWith Lisp you can have a productive dynamic language that compiles to native code, even OSes were once upon a time build with it.