Live data from Hacker News

Why I still Lisp

mendhekar.medium.com

141–150 of 240 posts

Re: Why I still Lisp

#141
Hi all,

I'm preparing release 250 of the TXR Language, the bulk of which is a Lisp dialect called TXR Lisp.

Release 250 adds compiler optimizations, like jump threading, some dead code elimination, and a few peephole reductions.

This work is finally possible because I had put it on hold due to not wanting to write such code without a pattern matcher, which we now have.

I'm fixing two bugs that were reported by a user, which will be nice in such a landmark release (250 releases, wow!).

The new structural pattern matching sub-language in TXR Lisp (new since 247 or 248) will be improved. Bugs are fixed. The way the @(or ...) pattern operator works has been rewritten, so certain corner test cases now pass. It generates better code.

There are will be some new features in the matcher too. The @[fun ...] flavor of the predicate operator now lets you capture not only the variable, as usual, but using an extra argument, the value of the predicate (which could be an extended Boolean with an interesting value).

For instance, is "abc" in the hash table htab? If so capture it as x, and also capture the value as y:

  This is the TXR Lisp interactive listener of TXR 249.
  Quit with :quit or Ctrl-D on an empty line. Ctrl-X ? for cheatsheet.
  Upgrade to TXR Pro for a one-time fee of learning Lisp!
  1> (let ((htab #H(() ("abc" "foo") ("xyz" "bar"))))
        (when-match @[htab x y] "abc" (list x y)))
  ("abc" "foo")
Here, htab is just being used as a function; any function will work that can take the argument "abc"; if it returns non-nil, then the predicate has rung true, the pattern has matched, and x takes "abc", and y the returned value.

By the way, to see quips like "Upgrade to TXR Pro for a one-time fee of learning Lisp!" you must add this to your ~/.txr_profile:

  (put-line (quip))

Re: Why I still Lisp

#142
post #136
post #17

> I have never had a static type checker (regardless of how sophisticated it is) help me prevent anything more than an obvious error (which should be caught in testing anyway). Obvious in retrospect is not the same as obvious. And such errors happen all the time, the same way without syntax checks typos happen all the time. And "caught in testing" is 2 extra steps removed from caught immediately by the syntax checker…

> What thing that violates a type check would be "perfectly fine to do"? Here is an example limitation of typescript's type system that I routinely run into while developing real code [1]. I look at it like this. If you consider all possible programs, some are invalid, some are valid, and some are valid and useful. A type system's job is to reject as many invalid programs as possible while accepting as many valid pro…

Sometimes the type system is forcing you to think in terms of what it is that you are passing around. In this case, getEmails() isn't expecting a group of students or a group of faculty, but rather a group of people that can be emailed. You can introduce an interface of that type and have it inherited by both Student and Faculty and use that in the method for clarity and type-safety without over-relying on union types: https://www.typescriptlang.org/play?ssl=1&ssc=1&pln=38&pc=30...

Re: Why I still Lisp

#143
post #87

Earlier quoted context omitted.

You might be one of those experienced developers who has gone through their entire career without ever meeting a well designed, beautifully architectured application, and therefore concluded, sensibly, that all real-world applications look like shit if you look inside, and you seem to have come to believe that this is the only possible way. I have a different experience. Code that is well designed makes mistakes look…

> a well designed, beautifully architectured application I've seen everything during my career, bad code with lots of bugs, bad code running stable. Nice code full of bugs, and nice stable code. The reason something was stable was never how the code looked, but how battle tested the product was. You will learn, don't worry. Plus, at a certain point, it's about tradoffs and compromises. I would love to see highly opti…

you assume a little bit to much about your discussion partners. calling them inexperienced etc...

this takes away the whole strength of your argument plus lets you sound like a douche.

plz fix

Re: Why I still Lisp

#144

> What improves (and guarantees) software quality is rigorous testing. To deliver high quality software, there is no other solution. This is 100% false. You can’t inject quality into a bad design via testing. You can’t guarantee quality or correctness through testing. Testing is the second worst place to find errors. You get a MUCH higher roi by producing thoughtful written designs and getting them peer reviewed. And…

I wonder how much experience you have in the real world. All of us developers had this thought at some point. I've seen terrible code with plenty of quick hacks on top of that, which was running very stable, because it was battle tested for years in production. What do you think will happen when you refactor such code to a better design? All juniors would think this is the best way to get a stable codebase. Reality i…

this is pure argument from authority.

I value testing, but primarily because (in years of experience, etc.) it makes code easier to refactor or reuse, not easier to make _correct_. Actually, this also applies to static types, which I also value.

But suitability-to-purpose (the best proxy for correctness that I've yet found) is far more determined by peer-reviewed design than by tests.

Re: Why I still Lisp

#145
post #11

> I have never had a static type checker (regardless of how sophisticated it is) help me prevent anything more than an obvious error (which should be caught in testing anyway). This is the static vs dynamic type debate in a nutshell. Personally I think Typescript hits a sweet spot of static typing by default with an escape hatch (via the `any` type) when you need it. I think more self-documenting code makes the trade…

It's like saying you don't need a spell checker becuase you never make mistakes. Pure hubris.

No, it's like saying "I can't remember the last time I needed to turn my document into a string literal embedded into the word processor's source code, so that a spelling error could be caught when the word processor is recompiled. I test my document using an easy-to-use run-time spell checking feature."

Re: Why I still Lisp

#146

Earlier quoted context omitted.

It's like saying you don't need a spell checker becuase you never make mistakes. Pure hubris.

No, it's like saying "I can't remember the last time I needed to turn my document into a string literal embedded into the word processor's source code, so that a spelling error could be caught when the word processor is recompiled. I test my document using an easy-to-use run-time spell checking feature."

This is not an apt analogy at all. You don't recompile your editor to get type errors. The question is type checking vs unit tests. If your text editor can type check as you type, the feedback loop is much tighter than recompiling and rerunning and possibly modifying handwritten unit tests.

Re: Why I still Lisp

#147
post #46

Earlier quoted context omitted.

It's pretty easy to do in Typescript and loses no type safety (without needing to assert or cast anything) type T = { [k: string]: number }; const t: T = { one: 1, two: 2, three: 3, }; const makeUpperCaseKeys = (v: T): T => { const keys = Object.keys(v); return keys.reduce((p, c) => { const key = c.charAt(0).toUpperCase() + c.slice(1); return { ...p, [key]: v[c] }; }, {}); }; console.log(makeUpperCaseKeys(t)); // { /…

That's great! Are you making the argument that I won't be able to find an example where doing some transform in a type-safe way is awkward in TypeScript, or just that this one example can be done in TypeScript? By the way, my example was meant to be more like User -> User where there are some string values and some other types of value. You want to do the transformation in a generic way, but still have the type-safe…

[deleted]

Re: Why I still Lisp

#148

Earlier quoted context omitted.

I 100% agree that disastrous codebases are every bit as likely in other languages. But it somehow hurts more in a lisp. I think that the syntax really is the culprit. In a language like Java, the Byzantine syntax and semantics enforce some minimum level of structure on the code. It's not much, but it's something, just enough to give an experienced programmer a few extra heuristics they can use to make sense of what t…

It feels like Lisp scales vertically and Java scales horizontally. Java scales for number of developers, its idioms and ecosystem make it easier to have tons of developers on a single project. Lisp scales on the size of problem that a small close knit team can solve. Things like the macro system in Lisp encourage defining your own problem specific DSL, which is great for individual developer productivity, but bad for…

Like the way those defclass and defmethod macros totally destroy programming at large.

Re: Why I still Lisp

#149
post #89

Earlier quoted context omitted.

> Macros modify code structure at runtime so obviously that is fraught with danger. You may have inadvertently misspoke, but macros operate at compile time, at least in the Lisps I have used.

If one uses a Lisp interpreter, macro expansion may happen at runtime. CLISP example: [2]> (defmacro add2 (place) (print 'add2) `(incf ,place 2)) ADD2 [3]> (let ((a 1)) (dotimes (i 4) (add2 a))) ADD2 ADD2 ADD2 ADD2 NIL [4]> As one can see the macro form is expanded four times at runtime.

This is a confusing example, because in a REPL steps of compilation and evaluation are interleaved.

Indeed, can you write a program for CLISP that works like this:

- takes one command line argument (a file name)

- reads in the given file, interprets it as Common Lisp code, expecting it to deliver a definition for the add2 macro

- then runs

   (let ((a 1)) (dotimes (i 4) (add2 a)))

Re: Why I still Lisp

#150

In other words, static typing is pointless. It has, maybe, some documentary value, but it does not substitute documentation on other invariants. For example, your invariant might be something like I’m expecting here a monotonically increasing array of numbers with a mean value of such and such and a standard deviation of such and such. The best any static type checking will let you do is “array[float]”. The rest of y…

Thank you for mentioning that and reminding me about two of my favorite projects, Eiffel and PyContract. (Is part of why DbC is so useful is because it's an extremely concise way to write assertions?) I'd love static typing systems if they allowed for DbC-style type declarations. There are times when the thing I need to use isn't a generic int, or even a short int, but an integer three or more. That's also type infor…

Dependent type-systems like Agda can do that. Unfortunately they are also a pain to write.

Fun-fact, you can use church-encoding to transform from your generic int to a "shape" based encoding for the slowest operations ever in quite a few languages (Python included).

Post reply on HN