Hacker News new | past | comments | ask | show | jobs | submit login
Show HN: Parinfer – a simpler way to write Lisp (shaunlebron.github.io)
674 points by undershirt on Nov 11, 2015 | hide | past | favorite | 134 comments

To copy a comment I made elsewhere: I'm seriously impressed. This is amazing.

Paredit always ended up being a requirement for me, but this takes it to the next level. What other editing problems out there could have excessive hotkey usage replaced by something automatic with the same level of power, I wonder? This is a great example of an area where user interaction experts can really have a lot of impact, and I think shows why engineers ought to be more accepting of disciplines like that.

Hi folks -- I've been working with Shaun on the tail end of this project.

Have an early prototype of Parinfer working with the Atom editor here: https://github.com/oakmac/atom-parinfer

It's pretty early software, but feedback appreciated :)

Parinfer + Atom -- what a dream come true. Awesome work. (Edit: just took it for a spin, and it "just works", even with atom-vim -- doubly awesome. I really feel like having to navigate parens while learning the language was such a barrier to diving in to ClojureScript. Cant wait to get started.)

This comment makes me so happy; thank you :)

I'm glad it "just works"!

Your project seriously makes me want to learn lisp.

Me too!

And I already wanted to learn Lisp. Because I kind of half-assumed this tool to be there already :-P

I always assumed, obviously Lisp didn't get this popular if people had to keep track of all their parentheses. Sure they probably had to in "the old days" (although I wonder even when?). It just seems like a tedious thing to have to do in order to work with such a consistently structured language.

Of course you can get most of it with highlighting matching parens and auto-formatting shortcuts. Like most languages.

But I kind of expected Lisp tooling to go the extra mile. Because it is that structured.

From my limited knowledge of Lisp, I figured some vague ideas on how such a tool would work / should be designed. It's kind of cool to see that the author's initial steps match up with that idea: define a grammar, some invariants, and "have at it" (ok, so I didn't figure that far). And then he made it work!

Maybe a silly question, but since the author is in this thread: Was it hard to make? :-)

BTW the idea of switching between these two modes is a very clever approach to keeping certain invariants invariant while still being able to modify the code--because the trivial way to preserve the invariant would be the tool immediately reverting your edit :)

I can't thank you enough for this! It's just awesome! I really enjoy learning Clojure / ClojureScript and with Parinfer it will be even more fun! Thanks

Wow. Could it also work with JavaScript?

Not really due to the fundamental difference between Lisp and JavaScript syntax.

You could borrow the idea of indentation inferring function scope structure and make a plugin that would modify JavaScript syntax accordingly, but I'm not sure that would even be desirable when writing JavaScript.

Parinfer is made possible by Lisp's unique syntax.

Check out Kent Beckman's Prune for ideas along this line: https://www.facebook.com/notes/kent-beck/prune-a-code-editor.... It's not quite the same since it's more like an enforced paredit, but it contains a lot of similar ideas and also enforces indentation.

I don't know what's more impressive: The work itself or the beautiful documentation which accompanies it. Very impressed!

For emacs, there's the electric-indentation-mode and the fantastic aggressive-indent-mode.


This reminds me more of Paredit, in that it handles s-expression aware source transformations, and not just indentation:


I would deeply love to see this kind of inference engine ported to emacs as an alternative to Paredit's chords

A more direct comparison for Emacs would be `adjust-parens`:


Wow! This is fantastic! This seems to do just what Parinfer does. Why isn't this mode more well-known?

This makes it even better:

    (defun my/lisp-dedent-adjust-parens ()
        (call-interactively 'lisp-dedent-adjust-parens)))
    (defun my/lisp-indent-adjust-parens ()
        (call-interactively 'lisp-indent-adjust-parens)))
    (local-set-key (kbd "<M-left>") 'my/lisp-dedent-adjust-parens)
    (local-set-key (kbd "<M-right>") 'my/lisp-indent-adjust-parens)
Now you can just M-left and M-right to adjust the indentation of any line, regardless of where the point is, and adjust-parens fixes the parens for you.

Wow, this is a fantastically documented and executed idea. I'm not enough of a Lisper to have an opinion on the content (though it certainly seems cool), but the presentation is top notch.

As a lisper, the content is similarly well executed. It's a rarity to see both in one place.

> Most programming languages have several syntax rules. Lisp has one: everything is a list.

Oh, not again.

The author is confusing s-expression syntax with Lisp syntax. Even s-expressions are more than lists (conses, cyclic conses, symbols, vectors, strings, various numbers, structures, ...) and the s-expression reader knows about more than pure s-expressions - for example comments.

Not every s-expression is a valid Lisp expression. For example (let "let") is not a valid Common Lisp expression. The syntax for LET is:

    let ({var | (var [init-form])}*) declaration* form* => result*
This is also using the syntax definition for 'declaration' and 'form'.

Lisp has built-in syntax (provided by special operators in Common Lisp) and arbitrary complex syntax provided by macros.

This is valid for other languages with a notation based on s-expressions, like Scheme or Clojure.

I can assure you the author of Parinfer is aware of this distinction ;)

That sentence is an oversimplification to give context to the rest of the content in that section. Should probably have an asterisk to clarify.

It's one of the sentences which creates endless confusions and a false image of Lisp. 'Everything is a list'. Oh, Lisp has only one data structure? Lisp is difficult to read, because it has no other syntax? Lisp is a primitive language and not usable for real programmers... etc. etc. It also creates the impression that even proponents of Lisp-like languages don't actually understand the basics...

Who is endlessly confused? Who suspects that the author of a neat lisp editor plugin has never written a non-trivial line of Common Lisp, Clojure, or Scheme? What are the chances that people in either category are also curious and excited to experiment with novel editing techniques?

> Who is endlessly confused?

Everyone who reads or hears this sentence. I've heard 'everything is a list' a zillion times already. It's just wrong. In every way.

A LISP program is a list of characters.

Actually not.

A Lisp program is data. The Lisp system does not care if it comes from a text file or if it is constructed as data by a program:

    (list '+ '1 '2)  constructs a program which can be evaluated.

I have thought about this response a bit, but, all I see here are more lists of characters.

Use Lisp and you will see.

If we're going to be super pedantic, the Common Lisp spec actually defines code as:

"code n. 1. Trad. any representation of actions to be performed, whether conceptual or as an actual object, such as forms, lambda expressions, objects of type function, text in a source file, or instruction sequences in a compiled file. This is a generic term; the specific nature of the representation depends on its context. "


We all knew what it meant, including the author. This is pointlessly pedantic.

I'm the first to call out grammar nazi's and pedantic crap. Despite that, lispm is right to call it out for a correction. It's a factually inaccurate statement that's gives non-LISP readers a misleading impression about what the language and its machine code are likely capable of. It's also spread like wildfire due to constant repetition as lispm noted.

So, it's worth mentioning and replacing with something more accurate.

It's not. Explain Lisp to people not by treating them as idiots who won't understand that not everything is a list. There are numbers, vectors, strings, and various other forms of syntax in Lisp.

   (john "123" 1)  consists of a list, a symbol, a string, an integer

   |hi there|  is a symbol

   #*1010101011  is a bit vector

   #2A((1 1 1) (1 1 1))   is a 2d array
and so on.

Also look up the current Scheme report and see its syntax definition. 'Everything is a list' is fooling the reader and treating him/her like an idiot.

I'm pretty sure people understand that "everything is a list" doesn't mean there are no primitive literal types in the language.

Um, no. That's not at ALL clear to a beginner.

If you pick up just about any book on Lisp, it's all about recursion and lists. I don't remember SICP talking about native vectors or hash tables. I don't remember Touretzky talking about those either (maybe it was just that I had an early edition (1988-ish?) or my memory was faulty). Certainly The Little Lisper/Schemer never talks about them.

The first book I remember talking about other primitives in Lisp was Siebel's "Practical Common Lisp".

There are quite a few pernicious fallacies the swim around the "everything is a list", "S-exprs are easy to parse because they're uniform" (oh, really? Try identifying a list in the presence of dotted pairs), etc.

> Um, no. That's not at ALL clear to a beginner.

But surely after like 10 minutes of doing anything with it?

I haven't even begun to learn Lisp, just know that it exists and can mostly intuit/read it when digesting articles on various CS-related topics. It's pretty clear that there's something more than that going on.

Otherwise a whole lot of things that make Lisp interesting don't make a lot of sense. Where does the meta-programming come from if it's all just lists? How can it not be horribly inefficient if it's really just lists? What's so great about lists if really all you have is just lists, anyway?

So I'm going to go ahead and claim that most people that are intrigued enough to want to learn Lisp, already know (or assume) this. Seems like a great hook to start, actually: What is it about Lisp that's so great if it's just made of lists?

Now from what I read in your comment, you got Lisp dumped on you in CS college? "Here's this thing you have to learn about" is a fine way to learn about stuff (so many super-useful topics I probably would never have touched if they hadn't been forced on me in CS college[0]). But without a personal motivation of "I read everywhere that this thing is so powerful, and I'm going to find out why", then indeed I can imagine how "everything is a list" can be a toxic thing to teach about Lisp, in particular to a class of students who are busy enough that they just want to pass the course. What if they forget most, except that bit?

[0] except for me, Lisp wasn't one of those. We got Haskell though. Except it came at a rather inopportune moment, switching curricula, had to tag along last moment with some friends for the assignments, crammed for the exam, somehow passed and promptly forgot what monads are again. boo, hiss. yes. And I still managed to learn a lot from it! :)

I'll hold my hands up and say I did have a knee-jerk reaction to the criticism but then I remembered when I started learning Lisp.

I did often wonder where the arrays, hashmaps and other data structures were. I remember I had my own practice problems that involved random access so a vector would have been more efficient than a list.

In fairness, I think you either will be far enough on your travels with other languages to intuit that Lisp implementations do have these primitives ("surely not? Ah, lo and behold, racket has a nice vector interface. Not sure about CL's hashmap interface..." and so on) or you will be so far on your travels with lisp to understand why you need this that you already know.

I don't think I would direct a complete beginner to programmer to this page.

The very first example of code in SICP is a non-list primitive type:

    > One kind of primitive expression you might type is a number. (More precisely,
    > the expression that you type consists of the numerals that represent the number
    > in base 10.) If you present Lisp with a number
    > 486
    > the interpreter will respond by printing5
    > 486

An array, a structure or a cyclic cons structure are just as basic as a list.

In Lisp the cons structure is actually the primitive. Lists are built on top.


> I'm pretty sure you're an idiot.

We ban accounts that do this. Please read the guidelines and post civilly and substantively, or not at all.



His reply to this comment is totally out of line and I see he's been rightfully banned. However the comment you're replying to was just a poor attempt at humor, not a personal attack:

> Explain Lisp to people not by treating them as idiots who won't understand that not everything is a list.

>> I'm pretty sure people understand that "everything is a list" doesn't mean there are no primitive literal types in the language.

>>> I'm pretty sure you're an idiot.

Please consider context before calling out people like this.

Hardly "pedantic" to point out imprecise language in a post about parsing source code. It's hilariously wrong when you consider the author's focus on Clojure, which introduces all sorts of wonky syntax.

Indeed the article begs for potshots from smug lisp weenies:

1) It's clearly talking about Clojure, yet leads with "Let's simplify the way we write Lisp". Them's fighting words in the Lisp corral.

2) Paredit clone, but only acknowledges that for animations.

3) No emacs version! (Understandable given #2 however)

>The author is confusing s-expression syntax with Lisp syntax.

Then again what he says is true for 99% of the cases, and a good simplification.

>Even s-expressions are more than lists (conses, cyclic conses, symbols, vectors, strings, various numbers, structures, ...)

Still expressed as lists when it comes to the syntax level.

> Then again what he says is true for 99% of the cases, and a good simplification.

It's not. Read it slowly: only a subset of s-expressions are valid Lisp programs. Examples for invalid Lisp programs, even though valid s-expressions:

    (cl:if x > 1 t nil)    ; IF takes 2 or three forms

    ((cl:lambda) (a) a)    ; not a valid lambda expression

    (cl:let "a let expression" ((a 1)) (+ a 1))   ; the second element should be a list of bindings

    (cl:defun foo args (length args))             ; arguments needs to be a list
    (cl:let ((a nil t)) a)                        ; a binding is a variable or a list of symbol/value
and so on.

Lisp syntax is not the syntax of s-expressions. Lisp syntax is defined ON TOP of s-expressions.

> Still expressed as lists when it comes to the syntax level.

Comments are not expressed as lists. Feature expressions are not lists. etc etc...

>only a subset of s-expressions are valid Lisp programs.

Sure, but the thing we're debating is whether "all s-expressions are valid Lisp programs" (that would be a miracle actually), but whether Lisp syntax is all lists.

And all those examples are still lists -- that the lists can also contain other items inside them, or that underneath they are implemented as cons etc, doesn't really change that.

>Comments are not expressed as lists.

They are not retained anyway when the strings are parsed to the "live" AST (AFAIK), so they are an exception to the other syntax in that too.

The page says:

> Most programming languages have several syntax rules. Lisp has one: everything is a list. The first element is a function name, and the rest are its arguments. Thus, the language is simply a collection of compile- and run-time functions, trivially extensible.

Step by step.

> Lisp has one syntax rule: everything is a list.

That's wrong. completely wrong. 'everything is a list' is not THE ONE syntax rule of Lisp. Lisp, like most other programming languages, has MANY syntax rules.

A defining feature of current Lisp dialects is even that the syntax rules are programmer extensible and thus Lisp has an unbounded number of syntax rules. Thus the complete opposite is true: Lisp has arbitrary many syntax rules.

> The first element is a function name, and the rest are its arguments.

That's also wrong. It always was. Lisp has since day zero supported more than just function call forms.

Valid Lisp expressions:

    "1 2"
    ((lambda (a) a) 1) ; (lambda (a) a)  is not a function name
    (defun foo () ())  ; defun is not a function name
    (let ((a 1)) a)    ; let is not a function name
> Thus, the language is simply a collection of compile- and run-time functions, trivially extensible.

I would not even know what that actually might mean...

I know you all mean well, and accuracy is important in general, but the level of pedantry in this thread kind of turns non-lispers like me off of Lisp. Eliding certain complexities is a fundamental principle of pedagogy.

Would you prefer that somebody sells you Lisp telling you, that there is only one syntax rule? Later then you easily detect that a) people think Lisp is unreadable/unusable because of this and b) that it's actually completely wrong and that Lisp cannot even be parsed with a conventional parser, because it has even a dynamic syntax which can be changed by the user and that this is even a defining feature of typical Lisp?

Lisp like most other programming languages is not defined by one syntax role.

One of the main features of Lisp is actually that it supports user-defined syntax - either on top of s-expressions (aka MACROS) and/or by changing/extending the syntax of s-expressions (aka READER MACROS).

Wouldn't you want to know that? Just let the user of this editor feature know that it mainly works on the list level and does not know of the full syntax of Lisp and that this is sufficient for a wide range of editing tasks.

The emacswiki for Paredit says:


> ParEdit (paredit.el) is a minor mode for performing structured editing of S-expression data. The typical example of this would be Lisp or Scheme source code.

> ParEdit helps keep parentheses balanced and adds many keys for moving S-expressions and moving around in S-expressions. Its behavior can be jarring for those who may want transient periods of unbalanced parentheses, such as when typing parentheses directly or commenting out code line by line.

It says what it does. It makes no claims about Lisp syntax.

Let's try to not oversell Lisp syntax - Lisp syntax has been controversial for decades and legions of students and programmers struggled with it. There is a reason for that.

Tell a student that Lisp has only one syntax rule, the list, and then he/she struggles a lot forming valid Lisp programs?

Typical questions:

    (if (> sin (a) pi) 'foo 'bar)
Why is above not working? Somebody told the students that Lisp only has lists and it still does not work?

    (cond (> (sin a) pi) 'foo
          (t 'bar))
Above does not work either. Wasn't Lisp syntax supposed to be totally trivial with just one rule?

Let's be honest, it's not the students fault. The syntax of Lisp is actually more difficult than just writing lists.

I don't think this is 'pedantry'. Teach Lisp to people or deal with programmer's typical problems and you'll see lots of these questions.

> Still expressed as lists when it comes to the syntax level.

alists are not expressed as lists.

Looks like what Jetbrains would implement if they implemented a proper Lispy language support.

Very nice.

Am I the only one who is incredibly annoyed by how Jetbrains IDEs indent code?! Really, the fact that they totally fail to indent even mildly broken code is infuriating. At least ten times a day I feel like yelling at webstorm "YES, I know that that code is broken, that there are two unpaired {s and one unpaired ', but I'll fix that F LATER! NOW I just want to type this code here and have it properly indented even if there's broken code 10 lines above it and 20 lines below it. I KNOW, and I DON'T care NOW!".

I just want to download stuff from my head to the editor before I forget it, then later fix the mess, and have the IDE/Editor still help me in the meantime. If it needs to temporarily revert to a caveman-style indent-like-the-previous-line or event to temporarily disable auto-indent, I'm ok with that, but don't horribly mess up what I type in failed attempts to semantically auto-indent broken code that I don't wanna fix right now...

No - you aren't the only one, this infuriates me sometimes. The worst is when you have a file that someone accidentally mixed indentations or something, or use 2 spaces instead of 4 (even 4 spaces seems to break for me) for continuation/promise stuff. I'll enter insert mode and it'll be in-explicably tabbed out 5-6 times further than it should and I have to exit insert mode and manually move over to the correct spot or finish typing the function in shit-mode then manually fix the indenting. There's been several times where I've given up in frustration and opened up VIM or sublime text because I don't want to deal with it anymore.

Parsing correct code is easy. Parsing broken code is really hard because they have no way to predict the mistakes people will make.

Just ignore it, and when you fix it, select the affected lines and use the auto-indentation feature. Why do you care how it ends up being indented before you fix it, if you are paying so much attention to the stuff you are trying to download from your head?

I'll be looking at integrating this into Cursive, definitely.

Not by Jetbrains, but https://cursiveclojure.com/

> Looks like what Jetbrains would implement if they implemented a proper Lispy language support.

Let's hope they do, soon!

Good to see more people working on editors for Lisp, but I don't really see this as an improvement over the (immaculate, IMO) Paredit for Emacs.

Yes, those of us who have been editing Lisp using Paredit-like commands for years [0] may not find that much value here. But I think we're not the target audience; the goal is to help get newcomers over the hump, and that will be a wonderful thing if it works.

[0] 35 years, in my case. David Chapman and I implemented balanced-parenthesis editing commands for Zmacs (the Lisp Machine editor) in 1980. To my knowledge, it was the first such implementation for a text editor; the Interlisp structure editor already existed, but was considered hard to use.

This Chapman, I assume?


I'm something of a fan. This article is great, about his history at MIT's artificial intelligence lab, Ken Wilber, Heidegger, and Buddhism.


Yep, that's him! Thanks for the links -- I had lost track of him and hadn't seen his blog.

:) Here he is on Twitter: https://twitter.com/meaningness

While sleuthing a bit on Google I realize he was also a contributor to the "UNIX-HATERS handbook." Weirdly, that was really fascinating literature to me as a ... 15 year old, maybe, in like 2004? In my Swedish teenage room full of messed up Linux and OpenBSD boxes, reading everything I could that seemed interesting and intelligent. That handbook, the C2 wiki, various mailing lists, Usenet groups, IRC channels... I attribute a lot of my personality and interests to this nerdy/literate heritage.

Yes. I'm in the UHH too :-) Bottom of p. 211.

This is a huge improvement imo, and something that should be seen as a great advancement in usability. We've gone from needing to use hotkeys (paredit) to not needing to use them and having the machine figure out what you want to do.

Maybe others have different opinions, but I find this way of doing things a lot more natural and usable. It's like an old Oblivion mod for archery that asked the question: "Why do other archery mods have a hotkey for denocking your arrow? We just automatically denock if you look at the ground. It just makes sense."

This. It may not be huge for someone who is accustomed to those hotkeys, but for everyone this is a big deal. Imagine not having to commit those hotkeys to (muscle) memory at all.

If it lets people write lisp with the same ease of writing Javascript or Python (i.e. without investing time learning a tool specifically for editing s-expressions), then that's an advantage over Paredit kinda like Sublime's advantage over Vim/Emacs.

Trying it out in Atom, it looks really promising. You just kinda start writing, like on the blank line at the end of a function body, and Parinfer fills in the parens depending on your indentation level in an intuitive fashion, merging your form into the tree above it.

In fact, it seems to strictly complement Paredit. Parinfer puts the parens where you want them, and Paredit is there for explicitly editing the tree.

Did I miss something and Sublime somehow got some advantage over Emacs? When did it happen and what kind of advantage, exactly?

Sublime Text’s advantage in this context is the advantage that all GUI text editors share, including Atom and GEdit. This advantage is a combination of being more familiar and having better defaults.

Some ways that Sublime is more familiar are that it uses the OS-standard editing hotkeys, such as moving by words with Ctrl-arrows or Option-arrows. It also uses OS-standard terminology, like “close window” instead of “kill buffer” and “paste” instead of “yank”. The result is that new users don’t have to learn anything to be productive – they just edit as if they are in Microsoft Word, while enjoying the programming-specific features of a text editor such as syntax highlighting and block folding.

The better defaults include easily creating more than one scratch buffer (just run “New File” multiple times), automatically balancing parens when you type, support for pixel-by-pixel smooth scrolling, and scrollbars that don’t confusingly shrink when you start scrolling past the end of the buffer. I’m sure Emacs supports all these things, but you have to manually configure it to do so first. Many users are scared off from Emacs after seeing that it requires up-front investment to get features that other editors already provide with no work.

> more familiar

To whom? There is still a huge number of incompatible text editor cultures. Mac bindings, Microsoft bindings, Wordstar, etc.

> better defaults.

There are dozens of "better" .emacs pre-cooked packages. Choose any. No need to stick to the out of the box defaults.

> OS-standard

Which OS?

> he result is that new users don’t have to learn anything to be productive

The "new" users had to learn all those "OS default" bindings and terminology first. Not that "new" in my book then.

> it requires up-front investment

They simply forgot their up-front investment into learning the defaults of their chosen OS. I understand that - I still cannot use Microsoft Office, can't be bothered to learn it.

So, the only advantage is familiarity to those who already invested a lot of time into learning something else. Nothing of a value for the new users.

Yes, pre-cooked packages of defaults make things a lot easier for new users, but not quite equivalent to GUI text editors. I don’t get the impression that most people being introduced to Emacs are told to use a package of defaults. I think a lot of users will want to try out Emacs, so they download Emacs, then try to configure some things they don’t like by Googling the specific issues. After they have too big a list of things they don’t like about the defaults, they go back to their old editor, without ever learning of the existence of defaults packages. Which is a shame.

Apart from defaults, I agree that GUI text editors provide no advantage to completely new users. But I’m not sure that “new users” of text editors, unfamiliar with OS conventions, is a category worth talking about – I think it’s really small. It shouldn’t take more than a year for a new computer user to absorb the OS conventions while browsing the web and writing documents. And how many people might want to try out Emacs within their first year of using a computer?

I guess that about 10% of eventual programmers started trying out programming in their first year of computer use – the other programmers started later in life. The number of fledgling programmers who care about editors enough to look into Emacs has to be even less than that – it’s probably something like 1% of all programmers. The other 99% of programmers will find GUI editors more familiar than Emacs, because they have already internalized the conventions.

> GUI text editors

Emacs is a GUI text editor too, btw.

I can be wrong, but my impression was the opposite - all the new tutorials I saw recommended one or another starter pack with all the bells and whistles out of the box.

> while browsing the web and writing documents

I'm not sure if a proportion of users who write documents in a specialised software (like Word) is significant enough. And web browsing is largely clicking, no hot keys are used in general, so no habits to be picked up.

Another thing to consider is that now more and more users are coming from mobile platforms, without any desktop exposure whatsoever. For them, any desktop conventions are equally alien.

Good point, I hadn’t considered the new generation of mobile-first users.

> I'm not sure if a proportion of users who write documents in a specialised software (like Word) is significant enough.

I thought that most computer users learn to use computers while in school, for which they use a word processor to write essays and reports for the teachers. From around 2004 to my graduation in 2009, my middle and high school’s teachers even required essays to be typed and printed, so that they wouldn’t have to struggle to read students’ handwriting.

I guess some students prefer writing essays on paper, but those students probably wouldn’t become potential Emacs users.

Am I missing a common backstory for programmers that doesn’t involve using computers to write reports for school?

To be honest, I'm not quite aware of the current school requirements here, in my days all reports were hand written. But I've seen quite a lot of young people (here in the UK, do not know about the other countries) who obviously got no defining exposure to any desktop software at all. It is almost funny to see people discovering the copy and paste idea for the first time.

And with all the tablets and smartphones, even the basic touch typing skill is now extremely rare among the young.

I dunno, I write Lisp, Javascript, Python with vanilla Emacs (no paredit), and out of those Python is harder to write than Lisp and Javascript because the latter are indented automatically by Emacs.

Having to indent stuff manually is a drag. Especially when you nest in deep with Python and need to close several levels of indentation. It's just inherently difficult to "measure" white-space with your eyes. With 2-space indentation which is used in Lisp, and naturally deeper nesting, it's probably even harder.

> kinda like Sublime's advantage over Vim/Emacs.

Sublime is trash compared to Emacs.

danneu wasn’t necessarily saying that Sublime is better than Emacs overall. He was referring to Sublime’s specific comparative advantage over Emacs. The relevant advantage here is that Sublime is better at being easy to learn by new users, because it follows conventions used by the OS and by other programs.

Wow, I totally want to do my programming with this now... is there support for matching indents on 'let, as with align-cljlet?

Taken a step further, a structural editor could prevent incorrect syntax outright, and even allow you to view/edit the structure of your code in ways that simple syntax-highlighted text cannot.

Here's one such experimental editor: https://github.com/darwin/plastic

Edit: I see now that Parinfer refers to Plastic under its Acknowledgements section. :)

I'm wondering what Parinfer would feel like if used when editing the expression to submit in a REPL. (In other words, it could be nice outside of source editors.)

This is a good point. I immediately dismissed Clojure when I played with the in-browser REPL http://www.tryclj.com/. Within moments, I imagined the daily plight of the professional Clojure developer tediously balancing parens like I had to do in that REPL.

Had I known how polished my workflow would be a year later with Paredit + Emacs in-buffer line-by-line code evaluation, or that tool-supported s-expression editing would let me write/refactor/move/nest code much faster than in other dynamically-typed languages, I would've stopped what I was doing and started learning Clojure immediately.

But you don't know any of that if you're someone going to http://www.tryclj.com for the first time.

Seems like Parinfer could be used in environments where you don't have Paredit available or, perhaps more importantly, where the user hasn't already credentialized in a niche tool for editing s-expressions.

In the Parinfer introduction, 'C Style indentation' is mentioned.

What I can't understand is why 'C Style indentation' isn't the default convention, at least in modern user-friendly Lisps. One of the biggest problems people have with Lisp is the readability of grouped parentheses, but the C Style indentation example shows you can write Lisp without them.

I get that it's nice when programs fit in less lines of code, but isn't readability more important than line count?

C brace style has nothing to do with readability. Indentation alone shows the block structure just fine; Python proves this.

The purpose of C brace style is to make editing easier in primitive editors that don't do delimiter matching. In such an editor, selecting where, in a long string of closing delimiters, to insert a new element requires counting the delimiters, which is tedious and error-prone. With delimiter matching, the editor does the work for you, so splitting delimiters across lines is completely unnecessary.

Eh, yes and no. Python at least has `elif` statements.

When execution control depends on the order of nested arguments, I find "c" style to really enhance the following contrived example, even with rainbow parens:

  (if true 
    (whatever this is an (example
       that is (kind of hard)
         (-> to 
           (read %))))
     (this is an ELSE but hard to figure out))

Your example arbitrarily indents and new-lines. If that's what's on the table, then nothing is really going to help you.

    if (x 
    > 100) { console
      .log('hello') } else 
    { console.log
When it comes to if/else and if you indent with some sanity, then lisp is like Python: if the 'else' branch is too hard to spot or if you forget the context by the time you reach the 'else', then your 'if' branch is simply too many lines long. Or you should flip the condition so that the short branch comes first.

Meanwhile, I can't even write your lisp example as-is in any of the editors I tried it in.

It's hard if you indent wrong.

Also: http://imgur.com/FnXXOXJ

Tell me the above picture is something people have problems understanding the structure of.

Lisp, has cond which is analagous to Python's elif

Also you have your indentation wrong; (this is an ELSE but hard to figur eout) should be one column to the left, which makes it significantly more readable.

Visual Studio's had delimiter matching for years, and will auto-indent based on levels of depth, will add the trailing delimiter, even with adding new elements, etc. C brace style with autoformatting comes in really handy when editing functions on the fly, because it becomes obvious what block you're working on, with no need to look at one parenthesis among many.

C style is profoundly less readable for someone who has taken to time to familiarize themselves with Lisp.

Even when you can't use a Lisp-friendly editor?

Really, all you need are highlighted matching parens, I can't think of a single programmer's editor that doesnt' do that.

Do you get that when you're reading through online tutorials?

You don't really need it when reading tutorials either. Rainbow, simple matching, or manually counting parens is very much helpful when you're editing code, not so much when you're reading, at least if the code follows standard formatting idioms. You really get used to it: http://www.loper-os.org/wp-content/parphobia.png I would even argue you don't even absolutely need matching despite its helpfulness since Lisp was done and is done on many primitive editors without such features including pen and paper. As a first order approximation, you have just as many parens (braces, brackets) as a C-like language, the opening one is just on the other side, and C too can be done just fine with primitive editors.

https://github.com/orthecreedence/highlight-lisp provides paren matching on mouse hover, I find it annoying but I can see how it can be useful to some.

When I started working on a Clojure web app full time, I forced myself to spend a week learning and configuring Emacs, and learning Paredit.

To this day I have not found a tool that works as well as Paredit for editing and navigating s-expressions.

Parinfer looks like a cool subset of Paredit's abilities. I'd love to see it expanded to include all of what Paredit can do.

EDIT: I was mistaken, Parinfer does things Paredit doesn't. They could totally work together, that'd be pretty awesome.

I see no reason they couldn't coexist. Parinfer to guess paren insertion; paredit to cover the operations parinfer can't infer.

I'm more concerned that Parinfer appears to be modal, based on whether you manage indentation or parens. This seems overly complicated; it would be nice if there's some elegant way to merge the features of both into one mode. But I don't know how to do this, and I haven't actually used Parinfer, so maybe there's nothing to worry about.

It looks like one of the modes is mainly intended for fixing unmatched parens before switching into the other mode.

>To this day I have not found a tool that works as well as Paredit for editing and navigating s-expressions.


Basically paredit on steroids.

That's a lot of paragraphs. Got a tl;dr on how it improves on Paredit?

>That's a lot of paragraphs. Got a tl;dr on how it improves on Paredit?

The readme is not "a lot" in the slightest, the first paragraph of is a perfect summary. I'm sorry for being rude, but if you can't even bother to read one measly paragraph, I'm probably wasting my time writing this comment for you. The first paragraph is barely even longer than your original comment (10 words longer)!

The readme also links to a list of features and an article with gifs. Additionally, I gave you an even shorter and simpler tl;dr in my original comment: "basically paredit on steroids".

I was curious too, so I took a walk through the documentation. I found this:


I think I might try it out. It seems by default it's less strict than paredit, though, so I'll have to tweak it a bit.

> It seems by default it's less strict than paredi

Yes, but there is a strict mode you can turn on. Personally, I use the default with a couple binds that make it a bit more strict, which actually make it very pleasant to use, such as:

    (global-set-key (kbd "C-<backspace>") 'sp-backward-kill-word)
    (global-set-key (kbd "M-d") 'sp-kill-word)
And these in modes derived from `prog-mode`:

    (local-set-key (kbd "<backspace>") 'sp-backward-delete-char)
    (local-set-key (kbd "C-d") 'sp-delete-char)

Unless we are looking at different pages, that Readme for smartparens is quite small.

You've done great work. But speaking as an old lisp programmer it doesn't seem useful.

Code, for me, is a means of communication with both the machine and the human reader. The machine doesn't care about lisp indentation but code format matters when trying to communicate with human readers. Communication with future readers, including yourself, is what makes programs maintainable.

Pretty-printing is fine since the code format follows a standard, which makes it easy to ignore and easy to read, generally a "good thing". On the other hand, there is information in the choice of code format, similar to the information found in a poetry format.

Properly indented code is "good code" and, over time, is likely to be what flows from your fingers regardless of the editor. But excellent code is an art form that requires thought. Lisp is a language where indentation is meaningless but shape communicates. It is not something to delegate to an editor.

Emacs people, I want this.

Then write it.

I would even find this useful when writing python and defining nested dictionaries and lists.

Wow, this is really something. I never really thought about it and assumed that paredit would be as good as it gets. But, this seems to show that is not the case. I really need to check this out.

Wow! This is really impressive! I can't wait until someone ports this to vim. I might even take a stab at it myself. Great work!

I'm curious about this point from the article:

> And alternative syntaxes (Lisps without parens) have faultered since they sacrifice some of Lisp's power that seasoned users aren't willing to part with.

Could Elixer be an example of one of these Lisps without parens? [1] Can anyone give an example of what kinds of Lisp powers are sacrificed in a syntax where the parens are implicit rather than explicit? I can't think of anything off the top of my head.

It seems to me that Parinfer, when working as intended, almost turns a regular Lisp into one of these parenless Lisps, by performing parens manipulation for us, which in turn allows us to treat whatever Lisp we're working with as if it was a parenless Lisp.

[1]: https://blog.8thlight.com/patrick-gombert/2013/11/26/lispy-e...

I think the author is talking about minor variations on Lisp syntax that include indentation-sensitivity, not about different languages that are homoiconic. Such variant syntaxes include i-expressions (http://srfi.schemers.org/srfi-49/srfi-49.html) and sweet-expressions (http://readable.sourceforge.net/), which the author mentions in the Acknowledgements. For example, here are some sweet-expressions:

  define factorial(n)
    if {n <= 1}
      * n factorial(- n 1)
This desugars to:

  (define (factorial n)
    (if (<= n 1)
      (* n (factorial (- n 1)))))
I think the Lisp power that the author is referring to is homoiconicity, and the corresponding ease of writing macros. For example, i-expressions sacrifice homoiconicity in some contexts.

But the author seems to have overlooked that sweet-expressions, which were developed later, do not sacrifice homoiconicity. A human reader can still easily understand the AST from reading sweet-expression syntax. The real reasons that sweet-expressions have faltered relate more to the increased difficulty of collaborating with other developers, the lack of editor plugins that highlight sweet-expressions correctly, and incompatibility with Clojure syntax.

Using parens just makes manipulating the AST easier, but doesn't necessarily remove the homoiconocity of a language. I've barely done any lisp programming, though I have done a fair amount of work with AST's and compilers. S-exprs lend to thinking of the structure of the code as data, useful for "lisp-ing".

Personally I don't care to write in lisp since I loose track of parens way too readily. This project might be very handy!

In the meantime I've come to view Julia as my goto lisp. Quite fun to be able to write hygienic macros, but still have a mostly familiar imperative syntax for common tasks. Actually, the disciplined (read limited) usage of macros in Julia is a big draw for me, since I've heard too many horror stories of macro readers and spaghetti code in large lisp projects. Interesting look at elixir, I'll have to play with it sometime.

I don't know it at all, but isn't Dylan a Lisp w/o parens?

Eh, not sure I like it. For this to work, they have to make the indentation part of the syntax. Otherwise stuff is way too ambiguous to infer the correct parenthesis. A result is that the programmer has to be intimately familiar with how the inference works and what the syntax of indentation is. I feel that this just shifts cognitive load from managing parenthesis to managing indentation and inference. From the documentation:

  The rules for what happens when inserting/deleting parens must be
  learned. Also, the case necessitating a "Paren Mode" comes at the
  cost of forcing the user to understand when and how to switch
  editing modes.
  Also, the preprocessor step performed when opening files will cause
  more formatting-related changes in your commit history when
  collaborating with others not using Parinfer.

  they have to make the indentation part of the syntax
The syntax remains unchanged. Parinfer only "infers" the structure of your code based on the same indentation that you typically would do anyway as part of formatting your code to be readable.

  shifts cognitive load from managing parenthesis to managing indentation
Yes, exactly :)

Love the fact that it is written in Clojure

In the example:

  (foo [1 2 3
        4 5 6
        7 8 9])
How does one change it to:

  (foo [1 2 3]
       [4 5 6]
       [7 8 9])

edit: Ah, it works if you put all the forms on one line. I suppose it would be considered non-standard to indent that particular syntax in such a way.

You could also just put a "[" in front of "4" and "7".

Parinfer will infer the closing brackets.

That yeilds

  (foo [1 2 3
       [4 5 6]
       [7 8 9]])

A beautifully written web site. It made me happy just to look at it.

I haven't been doing much Clojure or Common Lisp development this year but I am putting Parinfer on my look-at list.

If I go to lisp for day to day work, I plan on using the syntax from SRFI-110 to encourage other people to work with me: http://srfi.schemers.org/srfi-110/srfi-110.html

Even if the code at rest is in S-expression syntax, editing it in this syntax would be slick.

Very neat demo, I hope it gets integrated into the major Clojure IDEs soon as it could make the onboarding experience smoother. I'm happy with just vim though -- I never liked the fashion of editors inserting/deleting/replacing non-whitespace characters (even that took a while to get used to) when they think they can to 'help' me.

This is great! I would love to see similar functionality integrated into Dr. Racket.

Great improvement on dealing with the parentheses!

Is there a version of this site without the distracting animated text, so I can see what is going on?

The main way to see what's going is is the animated text -- because what's going on is live re-indenting of code.

I look at it and keep wondering why it hasn't always been this way.

What tools did you use to make the documentation? It's excellent.

Man I wish the paren management stuff for vim didn't suck.

This would make `git diff` an absolute nightmare.

I can speak to this as I've been using Parinfer on existing code for the last week or so.

There can potentially be a "big diff" when you run Paren Mode on a file for the first time, but that's typically a one-time event. The beauty of Parinfer is that most Lisp code already uses these conventions.

Once you start using Parinfer's Indent Mode regularly it feels crazy to write or edit lisp without it.

One of my plans for atom-parinfer[0] is to have a comment flag in a file that will automatically signal "use Parinfer on this file". Similar to JSHint inline configurations [1].

[0] https://github.com/oakmac/atom-parinfer [1] http://jshint.com/docs/#inline-configuration

How so? All it does is automate the maintenance of exactly the same formatting that the developer would otherwise produce by hand.

Not if you're using that style of bracing already. I'm guessing you have a different style convention?

"git diff -w"

As an aside, I love the lego diagrams.


Made just good enough to get a job Rejection

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