Live data from Hacker News

Lisp is Abstract Syntax

michaelrbernste.in

41–50 of 55 posts

Re: Lisp is Abstract Syntax

#41
post #16

What I think this is missing which was a huge part of the SICP course is that Lisp is probably the best language to write your own language in with a custom syntax tailored for the problem space you're working on. Even if it isn't trivial to do. An example is Clojure's Hiccup[0] where there's a whole new syntax for dynamic HTML generation. It's not a full new Turing-complete language, but it's a custom syntax and voc…

When I look at that sample, what strikes me is how much the "custom syntax" still looks like a bunch of S-expressions. How much flexibility does LISP really give you here? For example, say I wanted my DSL to use Python-style significant whitespace instead of brackets. Does LISP make that easy, or is my DSL restricted to using stuff that looks like S-expressions?

Racket is somewhat unique in this respect, but it allows you to create dramatically different languages as DSLs.

Consider this example of the experimental "2d" syntax:

  #lang unstable/2d racket
  (require unstable/2d/cond)
 
  (define (same? a b)
    #2dcond
    ╔═════════════╦═══════════════════════╦═════════════╗
    ║             ║       (pair? a)       ║ (number? a) ║
    ╠═════════════╬═══════════════════════╬═════════════╣
    ║ (pair? b)   ║ (and (same? (car a)   ║     #f      ║
    ║             ║             (car b))  ║             ║
    ║             ║      (same? (cdr a)   ║             ║
    ║             ║             (cdr b))) ║             ║
    ╠═════════════╬═══════════════════════╬═════════════╣
    ║ (number? b) ║          #f           ║   (= a b)   ║
    ╚═════════════╩═══════════════════════╩═════════════╝)
Yes, that big ascii-art graph is actually part of the code, not some sort of comment. The 2d syntax allows you to create ascii art truth tables which contain in them code (in this case, in the traditional paren'd style.)

(See http://docs.racket-lang.org/unstable/2d.html for a better explanation and more examples.)

Alternatively, here is an example of typed racket using sweet expressions:

  #lang sweet-exp typed/racket

  define: fact([n : Integer]) : Integer
    if zero?(n)
       1
       {n * fact{n - 1}}
(https://github.com/takikawa/sweet-racket)*

Re: Lisp is Abstract Syntax

#42
post #5

Earlier quoted context omitted.

Is grokking Lisp's parenthesized s-expressions actually difficult though? I think that the real problem is that developers believe that they will find it difficult before they try it, rather than actually finding it difficult when they eventually do try it. I don't think I've ever picked up another class of languages faster; even python took more effort from me. Basically, I think it's a marketing problem.

I'm a C/C++/Java guy. I didn't find the idea of Lisp or the basic syntax that hard. Where I ran into trouble was not the strangeness of the syntax, but the sparseness : "It takes a macro to write a decent loop? Isn't that telling you that your basic syntax is ridiculously impoverished?" I mean, yes, you can implement absolutely anything, but in the bare syntax, you're given absolutely nothing. Second trouble spot: La…

In common lisp, a for loop is reduced to a goto internally via a macro which manipulates the syntax tree. In C, a for loop is internally reduced to a goto after the code is transformed into a syntax tree (manipulated by a non-standard and ad-hoc macro implementation). The difference here is that C must first make the syntax tree before it reduces the tree while CL reduces it immediately (since lisp code is already a tree).

All languages must reduce to a limited ISA of primitives (or conversely, all HLL are built on small ISAs). Lisp does a lot of this conversion early on (because it can) while C does this much later (because it can't do it early). You're simply quibbling about how soon to do this conversion. LLVM does the same thing as lisp in that it reduces a seemingly large language into a small set of constructs (and then works to optimize this small core language). I would argue that a smaller core language is better because it is easier to reason about and easier to optimize.

As to embedded, iRobot corporation created a lisp variant called L (based on a subset of common lisp) to use on their embedded processors via a bytecode VM.

http://www.cs.cmu.edu/~chuck/pubpg/luv95.pdf

Check out shen lisp (link below). It has (to my knowledge) the world's only Turing complete static typing system. Racket also has a static variant. Common lisp can be made into the equivalent of statically typed if you (declare) all variables and tell it to fully optimize.

http://shenlanguage.org/

Re: Lisp is Abstract Syntax

#43
post #18

Earlier quoted context omitted.

I think those problems stem from the embrace of metaprogramming, the creation of DSLs, and language oriented programming. I don't think that Lisp's typical lack of syntax is to blame there.

Well, Lisp's lack of syntax stands in the way of using syntax to tell a story. Horrible as c++ might be in many respects, the elaborate and somewhat stereotyped syntax of the code some random person wrote does tell a story. If the code uses the horrific "one big loop" convention, it's fairly easy at least to get that that is what's going on. I've only occasionally scanned Lisp code but in my experience of this, it se…

Nearly my entire professional career has been spent using languages other than lisps, but I am not really sure what you mean by use of syntax telling a story.

Perhaps the subset of C++ used reveals something about the development team that wrote it I guess? But there are certainly analogous things in lisp. Is the code macro heavy or light? Was the developer trying to treat the language like an imperative language, or functional? Massive monolith functions, or many small almost mathematical functions? Comments, or no comments?

I think that C++ and Lisp might actually be relatively unique in that respect. You typically don't see much variety in Java (beyond "This code was clearly written by a C developer who wishes he could just use C for this", which comes through loud and clear sometimes), and even less in Python.

Re: Lisp is Abstract Syntax

#44

Earlier quoted context omitted.

I have to respectfully disagree. I have coded for years in a lot of C-style languages, mainly C, Java, Python, Ruby & JavaScript and I've been struggling with the Clojure book (and various tutorials) for over a year. It's not just marketing, it's a very different mindset and one I'm not convinced is ever going to appeal to a large class of smart programmers (yes I guess I'm saying I don't think I'm dumb and hope I'm…

I'm a fan of Rich Hickey, too. And I think Clojure is a solid language. But I wouldn't suggest Clojure as the entry point when seeking a overall understanding of Lisp. There's too much baggage and history swirling around it for explanations ever to be comfortable - e.g. even if Rich Hickey always makes convincing arguments, it's important to note that they are always arguments. That is there always seems to be at lea…

In learning Clojure first then Racket, it struck me how many good ideas came from racket.. and now how many are still being mined - typed racket being the obvious one.

Re: Lisp is Abstract Syntax

#45

Earlier quoted context omitted.

This one of the reasons why, as a Lisp programmer, I don't care much for Clojure. Three different bracketing constructs when one would do just fine. Now I have to go look up the difference between () and {} and [] just to emit some HTML.

That's funny. This is one of the reason why I don't care much for Common Lisp. Hashtables in particular are common as mud in programming, but I have to work with a clunky interface specific to each abstraction. Ironically this puts CL closer to Java and C++ than the likes of Python and Ruby.

Hashtables are common, if one does not have other choices.

For many uses of hashtables, lists are just as good.

Re: Lisp is Abstract Syntax

#46
post #5

Earlier quoted context omitted.

Is grokking Lisp's parenthesized s-expressions actually difficult though? I think that the real problem is that developers believe that they will find it difficult before they try it, rather than actually finding it difficult when they eventually do try it. I don't think I've ever picked up another class of languages faster; even python took more effort from me. Basically, I think it's a marketing problem.

I'm a C/C++/Java guy. I didn't find the idea of Lisp or the basic syntax that hard. Where I ran into trouble was not the strangeness of the syntax, but the sparseness : "It takes a macro to write a decent loop? Isn't that telling you that your basic syntax is ridiculously impoverished?" I mean, yes, you can implement absolutely anything, but in the bare syntax, you're given absolutely nothing. Second trouble spot: La…

Kind of funny that people in the embedded area use C, which has a very weak type system and the result of using C is usually unsafe (no matter how programmers try) - even though its supposed to be compiled with static type checking.

> "It takes a macro to write a decent loop?"

That's the usual way to introduce a LOOP. As most Lisp implementations are written in Lisp, most syntactic constructs are macros anyway - whether they are at the language or the user level. For many Lisp systems there is really no distinction between both.

> Dropping into a debugger is not an acceptable bug-handling strategy in my world.

For embedded programming Lisp can have a lot of problems:

* lack of compile time safety

* the need for Garbage Collection

* no low-level machine types

* more...

Since the nature of 'embedded' is changing, some of that might no longer be such a big problem. In some areas 'embedded' systems are suddenly actually full-blown connected computers.

Re: Lisp is Abstract Syntax

#47

I have yet to hear a good explanation why homoiconicity is a good thing or in any way easier to learn. My main problem is that you have to know all the same things, but they become unknown unknowns. Not being able to tell at a glance that the argument list in a lambda expression, as one of the most common examples, is doing something other than execute code is very confusing if you're expecting everything to follow t…

Not everything is follwing a (func arg1 arg2) pattern.

For example a LET binding is following a (LET ((var1 binding1) (var2 binding2)) body) pattern.

Re: Lisp is Abstract Syntax

#48

Earlier quoted context omitted.

I'm a fan of Rich Hickey, too. And I think Clojure is a solid language. But I wouldn't suggest Clojure as the entry point when seeking a overall understanding of Lisp. There's too much baggage and history swirling around it for explanations ever to be comfortable - e.g. even if Rich Hickey always makes convincing arguments, it's important to note that they are always arguments. That is there always seems to be at lea…

In learning Clojure first then Racket, it struck me how many good ideas came from racket.. and now how many are still being mined - typed racket being the obvious one.

I don't know how much Rich Hickey used Racket, but he used Common Lisp for several years and wrote some complex libaries for it. There is also a sketch of Clojure early on written in Common Lisp.

Re: Lisp is Abstract Syntax

#49

I have yet to hear a good explanation why homoiconicity is a good thing or in any way easier to learn. My main problem is that you have to know all the same things, but they become unknown unknowns. Not being able to tell at a glance that the argument list in a lambda expression, as one of the most common examples, is doing something other than execute code is very confusing if you're expecting everything to follow t…

I have yet to see any data that supports ANY programming syntax as easier to learn or in any way a good thing.

Knowing a few C-style languages, a few lisp style languages, and a few ML style languages, I have found unsurprisingly that the language I'm using most becomes the easiest to read.

But since all we have is anecdotia and talks about our feelings, cracks knuckles, I'll give my two cents.

I think ML style is the easiest to _learn_ to read. It's sparse, simple, and almost always obvious. It's probably my favorite to read, and I usually find myself able to read it quickly.

My favorite to write and edit is a lisp style. With paredit and vim, I feel like I can edit code effortlessly. Every time I'm back in a C or ML descendant, I find I'm always wishing I could easily grab this expression or that parameter, and whoops, don't forget that comma there, nope this line it is a semicolon, nope this line it's a period. The irregular shape of the code with a different character for each concept (period for chained method call, comma for chained list or argument, semicolon for end of line, etc) makes it very hard to edit quickly. With so many different representations it is hard to add keyboard macros to help you structure code.

Specifically, in C# and JS, I always feel like I'm just pounding the text like a blacksmith, with sparks of commas, periods, semicolons, colons, brackets, square brackets, and angle brackets flying around. With lisps, it's usually just parens, and with paredit and Vim's in/a parens commands, they mostly work for me, not against me.

That same simplicity of representation is why macros are so fluid and simple in lisps. Can macros exist in other styles? Theoretically, yes, but all the issues I mentioned would be barriers in the way.

Re: Lisp is Abstract Syntax

#50
post #47

I have yet to hear a good explanation why homoiconicity is a good thing or in any way easier to learn. My main problem is that you have to know all the same things, but they become unknown unknowns. Not being able to tell at a glance that the argument list in a lambda expression, as one of the most common examples, is doing something other than execute code is very confusing if you're expecting everything to follow t…

Not everything is follwing a (func arg1 arg2) pattern. For example a LET binding is following a (LET ((var1 binding1) (var2 binding2)) body) pattern.

Or in Clojure, I'm starting to accept that this common pattern is a good thing:

  (let [var1 binding1
        var2 binding2]
     body)
Post reply on HN