Hacker News new | comments | show | ask | jobs | submit | Slackwise's comments login

"Let's move forward, by moving backwards!"

The web is already a document system.

It doesn't need to be skeuomorphically constrained into a 'book' with cute page turning animations, and no ability to use a scroll wheel, shift-space to go back (looks like `space` is hardcoded in his script, but only works half the time), or any of the features you already have in a browser. (I wonder how accessible it is in a Screen Reader, too.)


YAML seems more preferable, since it would be far more readable when STDOUT is the shell.

Oh, and JSON is a functional subset of YAML, so you'd still be able to output as JSON and a YAML parser will read it.


Yea, except, Apple most definitely favors aesthetics over functionality.

Take the iPod shuffle:

- Gen 1 was minimal, usable, and a portable USB drive,

- Gen 2 was minimal and usable, but lost its portable USB drive functionality (required a cable to also be carried around), but

- Gen 3 was smaller for no reason, moved the controls to an earbud cable which was impossible to use while running, and cost extra to buy an adapter if you didn't want to use their shitty earbuds, and then

- Gen 4 returned to the 2nd Gen design, because Gen 3 was very clearly flawed.

Seriously, explain the 3rd Gen iPod Shuffle.

I can cite many examples where they've dumped functionality for aesthetics, like non-removable batteries, fully-sealed computers (latest Mac mini), etc, but this is the clearest mistake they've made where they had to actually reverse course because of their favoritism for aesthetics over functionality.


I'm not going to defend individual design choices as I wasn't party to the tradeoffs being considered - and I disagree with some of them myself. But if you are involved in any kind of design (and I would definitely include programming here), you will be well aware of how much goes into boiling down a set of compromises into something elegant and usable - and how hard it can be to communicate why some part of that was really the best choice and took a lot of deep thought and iteration to get there. And you'll also be aware that design is never finished.

More generally, Apple have taken what many might think of as an industrial design approach and applied it to consumer design in a more rigorous way than others. So a lot of thought about coatings and materials used for screens and bodies, packaging (part of the consumer experience), and so on.

To construct a plausible scenario around your point off the top of my head, reduced size is clearly a key functional feature of a portable device, and while I'm not defending 3rd gen shuffle, it would make sense that a device you might go running with would be better if absolutely tiny. And if you are on the run, there would be an argument for having controls on the cable rather than the device. I think these kinds of things are clearly getting a lot of attention as we see the designs are being iterated and previous mistakes corrected.

Likewise, things like sealed devices are absolutely functional design decisions from the point of view of creating a mass-produced device. The success of the ipad bears this out. It may appal me that apple will only completely swap an ipad with cracked screen, or that I can't upgrade RAM in my macbook - but I can understand that standardisation and non-customisation is key to things like a predictable user experience, manufacturing and supply chain, worldwide warranties. Apple have always been about this and it's why they manufacture both hardware and software. I won't buy the 12" macbook computing device myself, but for family members it might be the ideal laptop. Anything else and I know I'm going to get several more messages a week asking me why facebook and twitter aren't working.


This was the page that made me finally grasp why Lisp and s-expressions are relevant. After reading this about a year ago, I ended up picking up a Clojure book and now I'm enamored with s-expressions. I feel late to the party.

The last time I tried to learn Lisp (prior to reading this) was in like 2003/4 from some CLISP tutorial that scared me away from having nothing but math examples and zero explanation of the philosophy or design. It felt like an esoteric and purely academic language, and I brushed it off as not worth my time. (I was never really put off by the parens, and now I love them. Never understood that aspect of Lisp discourse. Once you learn ParEdit[1] you don't want to go back.)

Now I link this page whenever I want to explain to someone why there are "all these parens". It's dated, though, and associating s-expressions with JSON and JavaScript would probably be a more contemporary approach. Maybe I should rewrite this article for a modern developer audience.

[1]: http://danmidwood.com/content/2014/11/21/animated-paredit.ht... "GIFs of ParEdit in action"


There's a "lisp parens lol" thing among programmers that's so intellectually lazy. I once interviewed someone who I noticed had explicitly mentioned Lisp on their resume, and when as an aside I asked what their thoughts on Lisp development were, all they could muster was "Oh god the parens hyuck hyuck".


Other languages tend to get a free pass, but I take every chance I get to whine about JavaScript's three kinds of parens that I have to keep track of manually, and the convention of putting nearly every closing paren on its own line, wasting kilometers of space.


Truer for some languages than it is for others...

"Oh god, syntactically significant white space!"


I'm more bothered by Python's lack of homoiconicity (thus no good macro facility) and poor performance when compared to Common Lisp.

Python feels a bit like a toy Lisp with all the adult parts hidden.


Yeah that screen space, truly a limited resource. You should cram everything together and don't forget to be extra clever in the middle of the dense unreadable forest of sigils as well. It was hard to write, it should be hard to read.


While I agree that in programming we should break our code in logical paragraphs, just like in prose, such conventions (placing closing brackets on their own line) are detrimental for that purpose. For me this doesn't have anything to do with wasting vertical space, as it has to do with aesthetics.

I'm not really speaking for LISP, but in my projects what really bothers me are people that don't have common sense when indenting / formatting their code and so they start using IDE or build plugins, using common conventions and formatters that will never be able to understand the meaning of the code being formatted, making a total mess of other people' carefully crafted code. And we go round and round on this.


While your sarcasm is mildly amusing, your point doesn't apply.

I don't advocate writing cryptic code. Of course I prefer code that is easy to read. That's a major basis for my opinions on syntax.

Do you think Python's syntax is cryptic and hard to read, because of the lack of end parens? Or did you just misunderstand my point completely?


I don't know that it is intellectually lazy. It makes a lot of sense.

If a lisp dialect had a large, vibrant ecosystem on the scale of Python or Javascript, then a lot of people would see the parens, see the advantage of having them, work their way through it and eventually get used to them and even embrace them because they see a real payoff.

That's not the case with lisp dialects. The major payoff with lisp dialects is macros. But for most people, it isn't obvious why they are important. They are something you have to use to really get.

So the intellectually reasonable position for most people is to either ignore lisp or laugh at it. Meanwhile, you see endless articles like this posted over the years (not knocking the article itself), trying to explain lisp in a kind of reverence and terminology usually associated with religious texts. "Hey, brother, you just need to see the light".

I've been doing quite a bit of Clojure coding lately and I love it. I just can't see a lisp ever catching on. Actually, the project I'm working on is a lisp that does not look like a lisp but compiles down to Clojure. The parens aren't really necessary for lisp's best feature, as seen by Elixir. Here's a bit of my language:

    " " join([1, 2, 3]) count println


To "ignore or laugh at" a whole family of important and interesting languages because they aren't as popular as Python or JavaScript is exactly laziness, or at best pragmatic, but has nothing to do with intellectual reasonableness.


Why is being pragmatic not intellectually reasonable?


I'm not saying being "pragmatic" in this way is "bad" or "wrong," and since this is pretty much a total derail, I'll stop engaging in this thread. But, like, this is the actual thing you said that I was responding to:

"the intellectually reasonable position for most people is to either ignore lisp or laugh at it"

I said that such a position has nothing to do with "intellectual reasonableness" because it's barely an intellectual position at all. There is no propositional content; there is very little thought involved at all; it's a default "meh" position that is more accurately labelled "laziness."


One should not sneer or laugh at languages like Perl, COBOL, or similar, simply because there are others we like better, or are more popular.

I used to be a HUGE Perl fan, and discounted Python for years. I figured that I already knew Java, and since Python and Perl were effectively similar, it was a waste of my time to study both. I now regret that. As formative as that was for my growth as a programmer, I've loved coding in Python more than almost any other language -- and I delayed that discovery by a decade because I wrote it off as "effectively the same as" Perl.

Sure, it was pragmatic to focus on one language that I was learning and using. But the reasons I did so were flawed, IMO.


the parens seems pretty necessary for that expression, I can't even tell what it's doing...

it's joining the vector 1,2,3 with a space to make "1 2 3 ", right? so what is that count doing there? I'm not saying that lists are the end all be all of syntax (clojure has vectors for a lot of things specifically to reduce the parens), but you need something there to make it clearer


I could have explained the syntax.

If you are familiar with Python, it more or less is equivalent to something like:

  " ".join([1, 2, 3]).count().println()
Which, imo, reads much better than:

  (println (count (join " " [1 2 3])))
Of course, Clojure has the threading macro, but this language emphasizes it.


Or, rather, maybe it will read better, about a generation after the first crop of high schoolers start being taught

instead of



That should be

and that is exactly what they type on their calculators:

[3] [1/x] [sin] [log]

(either that, or I am getting old. Modern graphing calculators may have different input modes)


I get what you are saying, but when you are talking about programming languages as opposed to math or another domain, more people are familiar or comfortable with the former, hence the reason for numerous posts like the original having to explain why lisp's syntax is a good thing.


Posts explaining why Lisp's syntax is a good thing have to deal with moving the left parenthesis to include the function:

  log(sin(f(x)))) ->  (log (sin (f x)))
They don't have to evangelize function composition being indicated by nesting.


Clojure is weakly typed? That python won't work since it is strongly typed.


Key word being like. That syntax works in Ruby, Python, or JS with the right methods defined.


The mainstream may realize how syntax doesn't really matter. The FP push helps a lot already (map,filter,streamfusion instead of crazy for/while statements).


Why do you call for and while statements "crazy"? Because it's possible to write them wrong? Because you think it's crazy to have to write them at all? Why?


> it's possible to write them wrong

too easy languages to conflate a lot of logic into large side effectful statements. FP forces you to separate layers, and deforestation (when available) helps reclaiming space/time costs.


All right, but "can be misused" is not the same as "crazy".


Alright, that was my own misunderstanding of loop invariants and scope showing. That gave opportunity for traumas when I started reading imperative code.


Seems fair to assume pp calls them crazy because they don't compose.


I think most people have an irrational dislike of s-expressions, but that at the same time, s-expressions are not as good as their proponents think they are. There's a certain aesthetic "purity" to them that's seductive, but from a practical standpoint, it is quite reasonable to adapt syntax to common patterns. The issue with mainstream languages isn't that they do that, it's that they do it too much.

But there are syntactic schemes besides s-expressions that allow for good flexibility. For instance, in my programming language Earl Grey[1], I use this very simple sugar: `a b: c` <=> `a(b, c)`. So you can use this todo syntax if you want, and it will just work:

    todo "housework":
       item priority(high): "Clean the house."
       item priority(medium): "Wash the dishes."
       item priority(medium): "Buy more soap."
Interestingly this has one advantage over s-expressions: whereas Lisp editors usually need to specify a special highlighting/indent policy for keywords like `let`, here editors can just highlight/indent `a b: c` indiscriminately.

I also think a limited number of infix operators are worth defining in most languages, and I don't mean arithmetic operators (although I'm okay with them). I mean ubiquitous or easily repurposed operators like assignment/declaration, lambda, pairing, or commas. In my view, Lisp-like languages hold to standards of purity that are unreasonable (don't get me wrong, they are quite usable, just not optimal according to any useful metric).

[1]: http://breuleux.github.io/earl-grey/


I don't think that's much clearer than a lisp equivalent:

    (todo "housework"
        (item (priority high) "Clean the house.")
        (item (priority medium) "Wash the dishes.")
        (item (priority medium) "Buy more soap."))
Yours looks nicer, but if I wanted to operate on your todo there, it's not obvious how just by looking.

With the lisp, it's obvious: There's a list of 5 elements. The last three are 'items', each of which is a list of 3 elements.

The benefit of s-expressions isn't just that they're flexible in what you can write with them, but that they're easy to manipulate programmatically, and their structure is immediately obvious.


I would say there are too many distracting "tags" in that which may be unnecessary ("XML disease"). For instance, look how you just indicated with a tag that the elements of a list are "items". In Lisp!

   (todo "name" (item ...) (item ...) (item ...)).
Basically the symbol todo is enough of a clue about the structure, and the pure syntax can determine most of the rest, with possibly a modicum of keywords here and there.

  (todo housework  ;; symbols for naming!
    (:high "Clean the house")
    (:medium "Wash the dishes")
    (:medium "Buy more soap"))


I was thinking the same but using Rebol:

  todo [
      high: "Clean the house"
      medium: "Wash the dishes"
      medium: "Buy more soap"
And this is so easy to validate & use via the parse dialect that comes with Rebol.

Here's a validation example:

  todo-rule: [
      set task-name word!
      some [
          set item-priority set-word!
          set item-desc string!

  >> parse [bad] todo-rule
  == false
  >> parse [incomplete high:] todo-rule
  == false
  >> parse [incorrect high: "item1" "erggh!"] todo-rule
  == false
  >> parse [housework high: "foo" medium: "bar" medium: "baz"] todo-rule    
  == true


S-expressions are not obvious "just by looking" either. Don't forget you had to learn what they were and how they worked. You know that `(a b c)` is a list of three elements, that the first element can be extracted with the `car` function, and the rest with `cdr`, and so on. You also know that `(a b)` is shorthand for `(a . (b . nil))`, which helps a lot in knowing how to manipulate it. The fact that you are already familiar with Lisp taints your perception.

Not to mention Lisps, especially the new ones, throw obviousness out the window with merry abandon. Let's look at Clojure. You think it's obvious how to operate on Clojure? Here: `(let [a 1, b 2] (+ a b))`. What is that? I've mostly coded in Scheme, I don't know what square brackets are supposed to do. Vectors? How do I manipulate them and what are they doing in my let? And what does the comma do? Oh, nothing? Then why is it there? And if the comma means nothing are you telling me that if I want to list the names that are being defined by this form, I need to extract the even-indexed elements of a vector? Sure I can do that, but don't tell me you care about ease of manipulation.

Anyway, sorry for the rant ;)

I think the point I really want to make here is that sure, s-expressions are quite simple, but if I can explain how s-expressions work in a minute, and how my expressions work in five minutes, this isn't really a matter of ease of manipulation, this is a matter of laziness. If a language's source-to-AST rules can be fully explained in one or two paragraphs or a small table, and can be easily remembered, then that's all that matters. I think that `a b: c` <=> `a(b, c)` is trivial enough that it does not have any meaningful impact on ease of manipulation.


Mathematica is a pretty good example of a language that introduces some syntax without compromising on homoiconicity.

For example

  a := {1 + 2 - 10, 10, {1, 2}}
is just

  Set[a, List[Plus[1, 2, -10], 10, List[1, 2]]]


Rebol is another homoiconic language that has infix operators:

  >> 1 + 2 * 3
  == 9
The Rebol interpreter see this as:

  >> multiply add 1 2 3 
  == 9
Functions in Rebol have fixed arity, both add and multiple take two arguments. You can express the above with parens if you want to make it clearer:

  >> multiply (add 1 2) 3
  == 9
Rebols infix operators have no precedence they just work left to right (like Smalltalk). Use parens where needed!

  >> 1 + (2 * 3)
  == 7


For reference, an S-expression based syntax that could be used for this example:

    (todo "housework"
      (item :priority high "Clean the house.")
      (item :priority medium "Wash the dishes.")
      (item :priority medium "Buy more soap"))
Your syntax certainly has advantages, but one can easily prefer S-expressions in this case without appealing to vague values like "aesthetic purity," nor are there any blatantly obvious "practical" downsides to using a more fully parenthesized syntax.


I really like the Clojure's minimalistic EDN format syntax. In comparison, Scheme and Common Lisp seem like they have superfluous parens.


Been recently studying Lisp/Scheme, and I couldn't help but relate these "Quantum Pairs" with cons cells and the relationship described as a tree data structure. (Not equating them here, just a musing of mine.)


Speaking of misfeatures: I was scrolling down this page, wanted to go back up to re-read something, and the entire page just changed.

I wondered why for a second, then made a half-inch swipe to the left and discovered there's a "feature" to let me change the page for some reason, but it requires that I change the fundamental way I operate my phone/browser.

Tried to read the article again, and on the way down to where I was last reading, the page changed again. Closed the tab and won't bother reading the rest because I'm infuriated.

This is on a Nexus 5 with Android 5.1, so no, there is no rendering issue here, or lag in read of inputs. This is just an anti-feature that need not exist, nor is made obvious to the user that it exists and needs to be worked around.


I've found need for a note taking mobile app recently, but after trying to use Keep and seeing that it has zero organizational tools such as tags or folders, I just started to use Evernote instead.

Frankly, it is nearly impossible to recommend Keep when Evernote exists. Until they have, at minimum, some way to organize notes, it's just a pile of notes sitting in one window. But it would still be a hard sell when compared to all the Evernote features, such as the desktop clients that allow you to take screenshots and annotate them.

Edit: Oh, and there's also Geeknote¹ for CLI usage, as well as Vim plugins².

¹ http://www.geeknote.me/ ² https://github.com/neilagabriel/vim-geeknote


I've been using OneNote, solely because I can use a keyboard shortcuts to click+drag screenshots or pop up a new ad-hoc, unfiled note immediately. Does evernote do this?


If you disable the annotation tool popup after taking a screenshot in the settings, then yea, it creates a "Screen clip" note with the image immediately after you finish dragging the screenshot range. (Of course, you can annotate later.)


Google Wave was an XMPP-based protocol¹. It allowed communication and collaboration with revisioning. It could have been embedded into applications such as office suites, giving you collaboration and communication right inside the app.

Wave.google.com was an example product using said protocol. Since the protocol was barely spoken of, even by developers, everyone assumed the website was the (only) product. Since the website did a lot of things, and none of it well, often being compared to email, it flopped and the entire project folded..

Now the project lives on in obscurity under Apache: http://incubator.apache.org/wave/about.html

¹ Technically, the "Wave Federation Protocol", but anyone that really looked into Wave would know that the protocol was the most important element of the project.


> It could have been embedded into applications such as office suites, giving you collaboration and communication right inside the app.

You mean like google docs?


This just reminds me of how much I'd like to see Clojure on LLVM also.


PixieLang exists, and probably does most of what you'd want: fast boot, FFI and Clojure-style LISP.


Thank you so much for this reference. The moment I grokked Clojure, I immediately thought "someone should port this to LLVM". The JVM is awful in a thousand ways, and it is quite surprising to me that Rich Hickey would devote so much time to getting many details right but get this big one wrong.

Trying it out now ;)


As much as I don't like Clojure on top of the JVM, I don't think you can say that the man who created the 3rd seriously successful dialect of Lisp made a big mistake/

I count "mainline Lisp", which ended with Common Lisp, and Scheme as the other two; others might count Autodesk's and Gnu Emacs' embedded Lisps.

Clojure is even showing signs of becoming mainstream in a way no Lisp has been since mainline Lisp through sometime in the '80s, not counting Scheme's niches in language research and (temporary? one) education. Or perhaps even better.


I view the JVM choice as a pragmatic choice to encourage wider adoption rather than a technical choice. Possibly it eased implementation too having a high-quality GC, but overall the drawbacks are quite severe, because they outright preclude Clojure from being used in situations outside the "long-running server process" use case.

It is even possible that he viewed the JVM as a stopgap to be abstracted out when and if the language got popular. It seems they are moving in this direction with ClojureScript. Clearly he made this decision thoughtfully and consciously because he was an expert in C++ before he ever wrote a line of Clojure interpreter, and could have made it native if he wanted.

But the argument "Clojure is successful, therefore all his decisions must have been optimal" (caracaturing you a little bit) is obviously false. Replace "Clojure" with "Linux" or even "Windows" and you see the fallacy.


The fact that this is not Lispy is more surprising than the concept itself.



Applications are open for YC Summer 2016

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | DMCA | Apply to YC | Contact