9 ms·
You already use Lisp syntax
- ben0x539 12y agohey guys i think haskell is a lisp too
- nox_ 12y agoWhy was this downvoted when it clearly shows how this article is misguided? Just because a language uses parentheses for some of its constructions doesn't mean we can call Lisp syntax.
- Dylan16807 12y agoThat sure does look like lisp. It also looks like a way I would definitely not use to do arithmetic if I could avoid it. This is more of a cautionary tale of going too far in making programs do 'one thing' than it is an endorsement of lisp.
- robin_reala 12y agoIn Fish shell backticks for evaluation are replaced by parentheses. One step closer I guess.
- jimktrains2 12y ago$() = `` in bash and zsh too. Bonus that $() can be nested.
- lispm 12y agoLisp syntax is quite a bit more than prefix operators + postfix arguments. * s-expressions are a syntax for data * Lisp syntax is expressed on top of s-expressions, reusing s-expression syntax for data * Lisp has built-in syntax for several constructs: lambda, let, block, setq, if, ... Many programming languages have some form of prefix operators. Btw., some Lisps allow to omit outer parentheses in a Listener (aka REPL): CL-USER 30 > delete-file "/Lisp/foo" NIL
- arethuza 12y agoSpeaking of leaving parentheses out of lisp - you can go the whole way and have a whitespace lisp: http://draketo.de/light/english/wisp-lisp-indentation-preprocessor http://draketo.de/light/english/wisp-lisp-indentation-prepro...
- lispm 12y agoStuff like that exists for decades: For example RLISP: SYMBOLIC PROCEDURE SMEMBER(U,V); %determines if S-expression U is a member of V at any level; IF U=V THEN T ELSE IF ATOM V THEN NIL ELSE SMEMBER(U,CAR V) OR SMEMBER(U,CDR V); Which would be in Lisp: (defun smember (u v) "determines if S-expression U is a member of V at any level" (cond ((equal u v) t) ((atom v) nil) (t (or (smember u (car v)) (smember u (cdr v)))))) RLISP has been developed somewhere in the 60s/70s as a parentheses free notation for Lisp on top of Standard Lisp. Much of the computer algebra system REDUCE is written in RLISP.
- qu4z-2 12y agoThis strikes me as a much bigger and less obvious transformation than the one suggested by the grand-parent (although interesting none-the-less). Specifically, this seems to take semantics into account whereas the suggested representation is apparently purely syntactic. For instance, the transformation from IF U=V THEN T into (cond ((equal u v) t)) would seem to require an understanding of the IF construct and a mapping of infix operators to lisp functions at the least. Now, maybe this syntactic transformation has been around for decades too (the fact that I've independently toyed with the same idea suggests it's not uncommon to play with), and alternative Lisp syntaxes are quite interesting in their own right, but I do feel that the whitespace-lisp suggestion has merit in its own right (but again, I'm clearly biased). Essentially, it's an alternate syntax for s-expressions, not lisp.
- taeric 12y agoThis is directly addressed in the article. The main point was simply that prefix notation for all things isn't that confusing. In fact, the main place it is somewhat confusing is with the math operators.
- basdp 12y agoWell, if you limit yourself enough, almost any language is a 'lisp'. Maybe we should stop calling anything with parentheses a 'lisp'.
- pdpi 12y agoPerhaps it's meant as a joke, but "prefix-RPN" grinds my gears. Just call it "Polish Notation", instead of "prefix Reverse Polish Notation".
- VLM 12y agoLook on the bright side, when HP48 calculators were more common so RPN was better known, I heard a lot of "Reverse RPN"
- Jtsummers 12y agoSome of us just said that as a joke. Like the day we finally thought about the banks telling us to enter our PIN numbers and decided to embrace the redundancy and repetition.
- arethuza 12y agoI once worked on a project where I was writing Lisp, C and PostScript most days - quite an interesting combination.
- zokier 12y agoI though a pipeline would be more idiomatic way of doing this in bash. But my initial attempt resulted quite unreadable mess: $ cat <(echo 2) <(cat <(cat <(echo 10) <(echo 4) | +) <(echo 7)| d) | x 4 Is there any way of making that more readable? My variation of the C utility source code is here: https://gist.github.com/zokier/c55e9c9736009981b494 https://gist.github.com/zokier/c55e9c9736009981b494
- captainmuon 12y agoLet the operators take one argument? # 2*((10+4)/7) $ echo 10 | add 4 | divide-by 7 | times 2 4
- zokier 12y agoI do like that, it also makes the utility more filter-like. Here is that implemented in C: https://gist.github.com/zokier/6b43032afb248bef68b7 https://gist.github.com/zokier/6b43032afb248bef68b7
- richardwhiuk 12y agoBy that argument Objective C is using Lisp syntax [a b:1 c:2]. Besides, if you want to persuade me to use Lisp, then starting by comparing the syntax to the shell is probably a bad idea, as others have said.
- spion 12y agoYup. See http://clochure.org/ http://clochure.org/
- davidw 12y agoFrom that point of view, Tcl is even more lispy. set foo [somefun $a $b]
- networked 12y agoI recently discovered Tcl and it immediately struck me as a refinement of the "stringly typed" design behind the Unix shell. I've been wondering if it would be a good idea to try building a modern fish-style [1] shell aimed primarily at interactive use and one-liner expressiveness based on a Tcl interpreter. (I tried eltclsh and it's close but not quite that out of the box.) [1] http://fishshell.com/ http://fishshell.com/
- captainmuon 12y agoSure, you can write bash like that. Actually, if you shift the parenthesis a bit, you can write almost any language like that: (add 4 (mul 2 5)) vs. add(4, mul(2, 5)) But that doesn't mean you should write bash like that. In fact, it is (IMO) very bad style to nest $(). When people complain about Lisp syntax, it's only partially about the RPN or the parens, its about the incredible amount of nesting. Funnily enough, of all things bash offers an alternative paradigm. Instead of nesting, you use filters: # pseudocode echo 2 | mul 5 | add 4 For example, you can write: nerrors=$(mycommand | grep error | sort | uniq | wc -l) instead of: # pseudocode nerrors=wc("-l", uniq(sort(grep("error", mycommand)))) I find this paradigm of "do A, then do B, then do C" much easier to think about than the nested "do C on the result of doing B on A". I wish more programming languages would embrace that kind of coding, which is basically functional, but in imperative or data-flow order. You have aspects of that in C# (LINQ), SQL, and some others. I know you can achive something like that in Haskell though Monads and `do`, though it feels a bit bolted on as a concession to having to do imperative stuff in a purely functional language. (And as nice Haskell is, it will probably never have the use base that bash has...)
- Jach 12y agoIndeed having a chain is often nicer than a lot of nested stuff. And when your base language is an abstract syntax tree, it becomes pretty easy to write a macro to let you flatten a lot of things out (among a bunch of other neat things). If your complaint with a lisp is that there's too much nesting, you haven't seen enough lisp. Pretty much every lisp has an infix-math library somewhere, for the popular lisps there's probably at least a dozen, and they usually allow mixing in prefix-math as well because nuts to typing "a + b + c + d + e" when I can just type "(+ a b c d e)" or if I want to call functions anywhere in the middle. There's no reason you couldn't write your example using a threading macro in Clojure, assuming your functions are defined such that they take input explicitly as the last argument instead of reading a common stdin. (Or if they take it as the first argument, you use a different macro but the same syntax.) Your code just becomes (->> (command) (grep "error") sort uniq (wc :-l) Does anyone think (wc :-l (uniq (sort (grep "error" (command))))) is a better option? And instead of typing that out manually, I just used the REPL. user=> (use 'clojure.walk) nil user=> (macroexpand-all '(->> (command) (grep "error") sort uniq (wc :-l))) (wc :-l (uniq (sort (grep "error" (command))))) Even without macros you can still setup nice-looking chaining with generators and coroutines. "Too much nesting" seems like the wrong complaint.
- tomp 12y agoOh god, another barely valid non-argument about the superiority of LISP syntax. Well, guess what. Function name, followed by arguments, is not LISP, it's Mathematics. `A x` has meant applying a linear transformation to a vector (i.e. matrix multiplication) for a very long time. Furthermore, saying "it's like LISP but without parenthesis around it" is like saying "it's like Java but without parenthesis around arguments and commas between then" when you actually mean to say "it's just like ML". Finally, bash has infix operators (like `|` and `;`), which make it infinitely more readable than it would be without them. Really, if we can compare bash with any other programming language, it's ML.
- drunken_thor 12y agowhoa settle down, the article wasn't about the superiority of LISP syntax, it was more about how the syntax is not as weird as you might think.
- chr1 12y agoThe weird thing about Lisp syntax is that people try to find all kinds of justifications why not having infix syntax is ok. The fact that arithmetic can be written in weird form in other languages too isn't very interesting.
- emiljbs 12y agoThe weird thing is that some people feel that they need to find all kinds of justifications for why not having an infix syntax is OK. Arithmetic in Lisp-style is excellent and easy to read. Thing is that programming languages infix math is ridiculously bad compared to what I can do with paper and pencil. It's really just a really bad form of imitation and to me that irks me way more than just doing it in Lisp. Math written in PL:s is hard to read in general and I'd love to see an Emacs package that lets you show an inline picture as you mark a mathematical expression of LaTeX rendering it as 'regular' math.
- tobik 12y ago
- praptak 12y agoFor me there were one and a half tricks to get Lisp syntax. The first was the mental conversion to/from f(a,b,c) to (f a b c) which is just moving the opening parenthesis one token to the left and seeing both commas and whitespace as "something between the tokens that really matter". The remaining half was starting with Clojure. It is a Lisp whose constructs are really optimized towards dumping extraneous parentheses so it is easier not to get lost in the nesting levels.
- jeremiep 12y agoYou also don't need to quote data structures other than the list in Clojure since they evaluate to themselves. (foo '(1 2 3)) simply becomes (foo [1 2 3])
- lispm 12y agoJust like Common Lisp and Scheme. Common Lisp: A vector: CL-USER 34 > #(1 2 3) #(1 2 3) A string: CL-USER 35 > "1 2 3" "1 2 3" A structure: CL-USER 36 > #S(FOO :A 1 :B 2 :C 3) #S(FOO :A 1 :B 2 :C 3)
- brudgers 12y agoWhat I appreciate from a design standpoint...i.e. aesthetically is the `defn` special form versus `defun` and `define`. In Common Lisp, `defun` takes on the general form of the lambda: lambda (x)(+ x 1) defun f (x)(+ x 1) Syntactically `(x)` looks like it should be evaluated, but isn't because there are special rules for special forms, and each special form can have it's own rules: let ((x 7)(y 3)) (+ x y) is a whole `nother set of syntactical rules which are even more in conflict with normal rules of evaluation. Scheme, keeps the let and uses a syntax for `define` that mimics the function call rather than the lambda. define (f x) (+ x 1) f 1 In Clojure the use of a vector for `defn` arguments follows it's formal lambda form like Common Lisp and is very much consistent with Clojure's rules for evaluation. fn [x] (+ x 1) defn f [x] (+ x 1) Likewise Clojure's `let` syntax does not require wetware parsing to recognize what gets evaluated and what doesn't. let [x 1 y 3] (+ x y) What I am appreciating about Clojure as a language is that it prunes some historic artifacts from the Lisp family tree. Raw memory allocation with `cons` made sense when human memory could retain more facts than a computer's fast memory. This meant it was easy to think of useful programs too big to fit in memory. That's distinctly harder today where doubling fast memory is less than $300 for the vast majority of computers. Lisp was developed as a direct improvement over assembly. Clojure was developed as a direct improvement over Java over C++ over C over assembly. It's a rethinking of what a Lisp needs (when backwards compatibility is ignored). It's an interesting design.
- arh68 12y agoLisp... doesn't really have syntax. S-expressions have syntax: parens, whitespace, symbols, comments. S-expressions are for data. Lisp is a subset of the sexps. Lisp adds just one rule: a Lisp program is an sexp whose root node is a function symbol. Naturally, since sexps nest, Lisp programs can nest. The author demonstrates nested computation with bash's $( .. ) syntax. Lisp, by the nature of the sexps, is nested computations. I think the author almost hits the nail on the head here: > Our two basic rules — program-name-first and $()-for-composition — allowed us to explicitly specify the order of evaluation, so there was no need to do any fancy parsing beyond what the shell already provides. Sexps provide nesting/composition. Lisp just means program-name-first.
- lispm 12y ago> Lisp adds just one rule: a Lisp program is an sexp whose root node is a function symbol. Now you explain these three examples. All have a symbol at the start of the list. * (let foo bar) ; in: LET FOO ; (LET FOO ; BAR) ; ; caught ERROR: ; Malformed LET bindings: FOO. ; ; compilation unit finished ; caught 1 ERROR condition * (lambda a b) ; in: LAMBDA A ; (LAMBDA A B) ; ; caught ERROR: ; The lambda expression has a missing or non-list lambda list: ; (LAMBDA A B) * (defun foo (a) (+ a 10) (declare (fixnum a)) ) ; in: DEFUN FOO ; (DECLARE (FIXNUM A)) ; ; caught WARNING: ; There is no function named DECLARE. References to DECLARE in some contexts ; (like starts of blocks) have special meaning, but here it would have to be a ; function, and that shouldn't be right. Obviously the SYNTAX for LET, LAMBDA, DEFUN, ... is more complex than what you think. Looks like there is Lisp code where it is not sufficient to have a symbol at the start of an s-expression. There seem to be more constraints to the allowed s-expressions. For example the syntax for LET is: let ({var | (var [init-form])}*) declaration* form*
- arh68 12y agoYeah you're right, it's not turtles/functions all the way down. At some point, your functions are defined in terms of special forms. Your special forms will either be natively supported or they'll be written with a defmacro in terms of native special forms. The definitions can't be circular, of course: if defmacro was used to define if, then if cannot be used in the definition of defmacro. So my "rule" isn't really a hard rule. Macros/forms are the exception. But it seems more intuitive for me to think in terms of functions whenever possible, then to bend the rule when macros get involved.
- smoyer 12y agoThe filters you specify for LDAP searches were probably inspired by Lisp syntax too: (&(|(uid=smoyer)(uid=swm))(mail=redacted@gmail.com)) To be honest, I'm not sure why the test expressions are infix while the logical operators are prefix. My guess is that it allows a filter to be specified without whitespace.
- kermitdance 12y agoI prefer comparisons of XML and LISP syntax to counter people complaining about the latter, while happily applying the former to pretty much everything under the Sun (application configuration, data exchange, dependency mgmt, build mgmt, scripting...) I'm not saying LISP is good and XML is bad; but I've seen some baffled faces when pointing out the similarities.
- jlas 12y agoThis is silly, sh/bash natively support arithmetic operations with infix notation. He writes a contrived arithmetic solver in C to support his argument.
- espadrine 12y agoIn Scheme, SRFI 105[1] gives the ability to do math with infix operators. There's no reason you can't have your cake and eat it too! [1]: http://srfi.schemers.org/srfi-105/srfi-105.html http://srfi.schemers.org/srfi-105/srfi-105.html
- ktg 12y agoL++ is a programming language that transcompiles to C++. It uses Lisp-like syntax. Macros are supported via Racket's macro system define-syntax, define-syntax-rule and defmacro. L++ | https://bitbucket.org/ktg/l https://bitbucket.org/ktg/l
- Monkeyget 12y agoStopping at the syntax when talking about Lisp is pretty narrow-minded and completely misses what makes Lisp so great. It's like saying to a car driver that motorcycles are nice because they only have two wheels and thus take less parking space. Technically true but not what makes them exciting. When you describe to the coffee-drinking radio-listening commuter about taking corners and being one with the road he won't understand what the point is. But if he were to drive a bike around a circuit, oh boy! I'm probably going to fail miserably but let me attempt to explain cornering and being one with the road in Lisp. What's so great about Lisp? : its extreme malleability in the way you write code and the data it uses. Code and data are the exact same things in lisp. They are represented the same way : lists represented with braces around them who can be nested. It's called s-expressions and they are in the form (<operator> <operand1> <operand2> <operand3>). There is no fundamental difference between code and data they are just list represented as s-expressions: (list 1 (list 2 3)) (+ 1 (+ 2 3)) Another example : (task (time 14 00) (log "beginning of task") (job (backup-files (important-files-in (list-files)))) (job (delete (list-files)))) Quick, what's that above, code or data? How about both? The one nice thing about s-expressions (sexp) instead of classical curly braces is that the code written in sexp IS ITSELF the abstract syntax tree of that code. For example, think of a function function add(a, b){return a+b;} You could convert this function into its syntax tree like this : (define-function (name add) (parameters a b) (body (return (+ a b)))) If we simplify things a bit we end up with : (defun add (a b) (+ a b)) Lo and behold, the example above IS Lisp code. Is that code or data? How about both? The syntax of Lisp is the same as its internal represention. That's called homoiconicity. What's so great about that? Well, mix that with macros whose language is Lisp itself and can do anything with s-expressions and you end up wielding great powers. A simple example. Let's go back to our task example. We can treat it as data : //not actual lisp code but you get the point var my-task = (task (time 14 00) (log "beginning of" ) (job (backup-files (important-files-in (list-files)))) (job (delete (list-files)))) my-task is now a list containing sub lists representing a task. What if we did this now : //not actual lisp code (defun time (hour minutes) (print "%d:%d" hour minutes)) (defun log (string) (print string)) //we say that task is a function //that should call each list it contains as a function (defun task () /*execute each list it contains*/) //... Now we can just do: (my-task) What do you think is going to happen? Yes, the data, the task is being executed. Now for the last touch : add to Lisp a powerful macro system that can take any s-expression (any list) and transform it any way it see fits and you end up yielding great power. What's that language? It's Lisp itself. Code is data. Lisp code evaluting other lisp code. I am so enlightened. Not enlightened? Didn't get anything out of my post? Then give Lisp a try! You have to dive into Lisp to be able to get it. As Eric raymond put it : "Lisp is worth learning for the profound enlightenment experience you will have when you finally get it; that experience will make you a better programmer for the rest of your days, even if you never actually use Lisp itself a lot." - ESR
- theothermkn 12y agoI don't know if Rich Hickey said it first, but he said it well when he noted that programmers get really upset when the parenthesis is on the left side of the function name, instead of the right side. DoSomething(an_arg, another_arg); vs. (DoSomething an_arg another_arg) I'm not sure the second is markedly less readable than the first.