HNHacker News
TopNewBestAskShowJobs

kbp

807 karma · joined October 19, 2016

submissionscomments
kbp··on Show HN: Lisp Shell
It only swaps; you can use pushd and popd if you want a stack.
kbp··on Show HN: Lisp Shell
I've never used it as a shell per se, but another little tweak I do sometimes for shell script type things in Lisp is install a read macro like

    (set-macro-character
     #\$ #'(lambda (stream char)
             (declare (ignore char))
             `(uiop:getenv ,(symbol-name (read stream)))))
This lets you read environment variables like $home, and write to them like ordinary variables, eg (setf $message "hello"). It reads the variable name as a Lisp symbol, so by default it will be upcased; this happens to be convenient for environment variables, but as with any symbols in Lisp, you can escape lowercase characters using either \ before the character or |'s around the whole symbol, or you could change the readtable case, or just preserve case initially in the read macro.
kbp··on Carp: A statically typed Lisp, without a GC, for real-time applications
I think for a lot of people, they "learned Lisp" from the Little Schemer and stopped there.
kbp··on Carp: A statically typed Lisp, without a GC, for real-time applications
And while it didn't make it into the Common Lisp version of LET, there were versions in earlier dialects that supported destructuring. For example, the Maclisp reference manual's description of LET[0] says:

It is permissible to place an s-expression pattern in place of a symbol in the (sym init) form of an element of the bvlspec. The symbols in the pattern will become bound to the matching elements of the initialization (see DESETQ). This kind of pattern-matched assignment is called destructuring.

    (let (((a b) '(1 2)))
      (cons b a))
    => (2 . 1)
0: http://www.maclisp.info/pitmanual/contro.html#5.6.1
kbp··on Carp: A statically typed Lisp, without a GC, for real-time applications
> I think most modern programmers prefer explicit destructuring and taking an element from a collection by its key rather than excplicitly traveling node links using car and cadr.

Then they'd be happy with Lisp from 40 years ago. Common Lisp (which was not the first to have either feature) has DESTRUCTURING-BIND (as well as some other constructs like extended lambda lists and within LOOP) where you can use destructuring, and it has generic sequence functions that work on more than lists like MAP, REMOVE-IF-NOT, REDUCE, etc, as well as lookup functions for getting things out of key-value maps (list-based or not) by key, or from sequences by index. Explicitly cdring down lists is mostly only done in introductory textbooks.

It feels like a lot of Clojure advocacy is written in terms of this "Lisp before Clojure" strawman of some minimalist Scheme subset. Lisp has had arrays, dictionaries, records, etc (with literal syntax and proper accessors), as well as destructuring and generic sequence functions, for almost half a century (more than half a century for some of that). Whether or not you prefer Clojure's syntax for those things, Lisp had those things long before Clojure existed.

kbp··on Lisp Game Jam 2018
As a side note, Scheme originally offered ASET (SET) but not a SETQ equivalent (they hadn't adopted the ! convention yet), saying: "Those of you who may complain about the lack of ASETQ are invited to write (ASET' foo bar) instead of (ASET 'foo bar)."
kbp··on Lisp Game Jam 2018
> I wouldn't consider something a dialect unless they were similar enough that most code that works in one works in the other with minimal modification.

I agree, but Scheme passes this test more than you might think. When it originally appeared, it really didn't stand out from the crowd of Lisp 1.5 successors that much at all. It even piggybacked off of its host Maclisp implementation, directly calling Maclisp functions extensively from Scheme, to provide any functionality that there wasn't any point re-implementing (ie, most of it). It was basically just a Maclisp package.

Modern Scheme still has a lot of features in common with Maclisp of this time (and by extension Common Lisp), like DO (although Scheme's do has slightly different semantics because it's a macro over tail recursion rather than gotos; subtle differences like this are to be expected between dialects), and it's still based off list structure in exactly the same way that Lisps always have been, so there's still CONS, CAR, CDR, RPLACA (renamed set-car!), RPLACD (renamed set-cdr!), NCONC (renamed append!), and so on.

Scheme's lexical scoping also made it back into mainline Lisp, and was a pretty big contribution to Common Lisp. A lot of features like CLOS, SETF, and DEFMACRO (none of which were in Lisp 1.5) are very commonly provided by Scheme implementations.

Using the historical argument, there's no question at all that Scheme is Lisp. The majority of ancient Lisp programs can be run under modern Schemes with simple compatibility packages. When all the other Lisps either merged into CL or died, though, Scheme continued to be actively used, and as time went on the Scheme community shared less and less code with the mainline Lisp community. Some people argue that with the modern state of things it's not really useful to talk about Scheme as Lisp now, because they kind of "left" Lisp and went off on their own, philosophically. Scheme definitely began as just another Lisp, though.

kbp··on Lisp Game Jam 2018
> i just started learning Common Lisp a couple of weeks ago. Coming from a strong OO programming background, i can honestly say it is a completely different mind-set.

You might not see it much in beginner materials, but idiomatic Lisp code tends to be fairly object-oriented, using the Common Lisp Object System (CLOS). CLOS is still a bit different from OOP in a language like Java, though: it's a much more powerful object system.

kbp··on Lisp Game Jam 2018
You can always just use a C library directly through the FFI if there isn't an obviously good Lisp option for what you're doing. You're probably not the only person trying to do whatever you're doing in Lisp, though, and asking on some online forum for Lisp users usually yields good suggestions.
kbp··on Why Does “=” Mean Assignment?
> In math, "a = a + 1" isn't the same as "1 = 2". The issue isn't equality, it's that you're trying to rebind a bound variable, which isn't possible.

"=" means equality in math; a = a + 1 is the same as 1 = 2 because if you subtract a from both sides and add 1 to both sides you get 1 = 2.

Lambda calculus has the concept of binding variables, but it doesn't use "=" for that, it uses application of lambda forms. It's the same idea that's applied in some variants of Lisp, where LET is a macro such that (let ((x 1) (y 2)) ...) expands to ((lambda (x y) ...) 1 2).

The way it plays out is that rebinding is perfectly fine, because it's not really any different from binding in the first place. The same way that

    (let ((x 10))
      (f x)
      (setf x (1+ x))
      (g x))
can be re-written as

    ((lambda (x)
       (f x)
       (setf x (1+ x))
       (g x))
     10)
That can itself be re-written as:

    ((lambda (x)
       (f x)
       ((lambda (x)
          (g x))
        (1+ x)))
     10)
If you'd like to read more about this sort of thing, Sussman and Steele's "Lambda: The Ultimate Imperative" is a good starter: http://repository.readscheme.org/ftp/papers/ai-lab-pubs/AIM-...
kbp··on Why Does “=” Mean Assignment?
> And most BASICs, though some (most?) required the keyword LET to introduce an assignment, as well.

LET was virtually always optional; an expression by itself on a line (like 'X <> 10') is a syntax error anyway, so removing LET doesn't introduce any ambiguity.

kbp··on Why Does “=” Mean Assignment?
In the original Smalltalk implementation, the character corresponding to _ in ASCII was a left facing arrow, which Smalltalk used for assignment at the time.
kbp··on Making a Statically-Linked, Single-File Web App with React and Rust
For sure, and its standard library equivalent was very, very good for the time, just not by 2018 standards.
kbp··on Making a Statically-Linked, Single-File Web App with React and Rust
The "decent standard lib" part is debatable, especially if you don't slip on the "targeting multiple platforms with ease" part.
kbp··on Suspect in YouTube Shooting Posted Rants About the Company Online
> There's a huge difference between being silenced and being refused ad placement on your videos.

If there's a huge difference between the impact that being silenced has on someone compared to having their primary source of income abruptly taken away, I would expect the latter to be worse for most people.

kbp··on The Rise of Worse Is Better (1991)
It's mentioned at the top of the linked page, but just to highlight it, this is only an excerpt from the longer piece "Lisp: Good News, Bad News, How to Win Big" which was written in 1991 and talks at length about the then-current state of the Lisp world and its future. The full article is well worth a read: https://dreamsongs.com/WIB.html
kbp··on Reddit 1.0 source code
> Is this typical to construct HTML in Lisp? This feels incredibly verbose and error prone, not to mention confusing and hard to grok. Good luck having a designer mockup/write HTML.

Do you mean that (:td :colspan "2" "username:") is verbose and error-prone compared to <td colspan="2">username:</td>, or what are you comparing it to? That code is probably denser than I would have written it, but I don't see any issue related to the fact the HTML is being generated from Lisp.

This example doesn't take advantage of it, but writing HTML in Lisp is easier and less error-prone than regular HTML, because you can abstract patterns and factor things.

kbp··on The Oforth Programming Language
> I realise it's actually a lot closer to Smalltalk than to Lisp -- you have a built in editor, you build memory images that you constantly work with, all the code is decompilable so you can refactor easily, etc, etc

Lisps often provide built in editors; Common Lisp even has the standard function ED for invoking one[0], but like most of the "environment" functions its behaviour is left almost entirely unspecified. Lisp is also usually developed in an image-based fashion. Images are one of the features that separate Lisp and Smalltalk from almost everything else, not one that separates them from each other. Some Lisps provide access to source code from function objects, with varying degrees of integration, and again, Common Lisp provides the standard function FUNCTION-LAMBDA-EXPRESSION for this purpose[1]. They don't generally work via decompilation, but neither does Smalltalk.

0: http://www.lispworks.com/documentation/HyperSpec/Body/f_ed.h...

1: http://www.lispworks.com/documentation/HyperSpec/Body/f_fn_l...

kbp··on What can we learn from how compilers are designed?
> AList's used as a map. Probably the worst possible structure for representing a map.

They're more flexible than hash tables and often faster; what makes them so awful? They both have trade-offs that make them better and worse in different contexts, depending what you're optimising for.

kbp··on Portacle – A Portable Common Lisp Development Environment
> > Perhaps you had problems with the concepts of Lisp packages (namespaces)?

> Rather unlikely. The namespaces are pretty easy to understand conceptually, and their interface is pretty minimal.

Packages can definitely give beginners trouble. I don't think it's that uncommon for newcomers to Lisp to have REPL sessions like this:

    CL-USER> (ql:quickload :iterate)
    (:ITERATE)
    CL-USER> (iter (for i below 10) (collect i))
    ;; Error: 3 undefined functions and two undefined variables
Then they find out they need to use the package first:

    CL-USER> (use-package :iterate)
    ;; Error: 3 NAME-CONFLICTs saying that the symbols ITER and friends
    ;; are already accessible
Then they throw their hands in the air about how frustrating Lisp tooling is. For a less obvious example, imagine they had just been using LOOP normally at some point in the past in that REPL session before trying to bring ITERATE in. Once you understand how symbols and packages work, it's easy to see why it works the way it does, but it's also easy to see how a beginner could get totally lost.
kbp··on Regular Expressions – Mastering Lookahead and Lookbehind
It's especially nicer in Ruby (which got it from Perl) where you can use whatever delimiters you like for regexes, with /abc/, %r"abc", %r{abc}, %r#abc# and so on all being equivalent, so you can just about always pick something that won't clash with the characters in your pattern (You can even use spaces as the delimiters, which looks terrible).
kbp··on Regular Expressions – Mastering Lookahead and Lookbehind
But when most of the commonly used "regular expression" libraries aren't regular, I think if you really mean solving something with only regular expressions, you should probably specify that explicitly. The term's been corrupted enough that using it by itself to rule out things like backreferences isn't clear communication.
kbp··on How knowing Lisp destroyed my programming career (2006)
As well, dynamic typing is much less of an issue in Lisp than it is in most other dynamic languages because the debugging and error handling features are really that good; they pick up most of the slack that the less-present type system creates. It would still make a lot of static typing proponents uncomfortable, of course, because not nearly as much is being statically verified. I think that the reason people become so infatuated with static verification (and testing) (not that they're bad things or anything, but just the reason they get put on such a pedestal by some people) is frustration with languages like Python, Ruby, and Javascript, which all lack a lot of the tooling that Lisp or Smalltalk has to make working in a very dynamic environment not only tolerable, but preferable. People get frustrated with the lack of tooling around mainstream dynamic languages' dynamism and attribute it to being frustrated with the dynamism itself.
kbp··on What Made Lisp Different (2002)
> Clojure is not based on CONSes but you have CAR and CDR they are first and rest.

CAR and CDR are operations on conses, so you can't have them without conses; that's like having sqrt without numbers. Lisp has FIRST and REST for operating on lists, and so does Clojure. Lisp also has CAR and CDR for operating on conses, but as Clojure doesn't have conses, it doesn't have CAR and CDR, either.

> Processors are no more based on accumulator and decrement registers

CAR and CDR were named for 'contents of address part of register' and 'contents of decrement part of register', not anything about accumulator or decrement registers. I'm not sure where you heard that processors don't have accumulators anymore, but that's definitely not true. The reason Clojure doesn't have CAR and CDR doesn't have anything to do with obsolete processors, though.

> Clojure is based on immutability like Scheme

Scheme is not based on immutability.

> CL is often used in a mutable way (see the shameful f-set).

Do you mean SETF? FSet[0] is an immutable data structure library for Common Lisp. A lot of Schemes have SETF, too, by the way, there's even an SRFI[1]. But SETF is just so that you can have one generic assignment operator; standard Scheme has plenty of commonly-used, destructive assignment operators like set-car!, set-cdr!, vector-set!, etc.

0: https://common-lisp.net/project/fset/Site/FSet-Tutorial.html

1: https://srfi.schemers.org/srfi-17/srfi-17.html

kbp··on What Made Lisp Different (2002)
> Of these five, clojure only has two (atom and eq)

You can't have atom without conses (well, it would just be (lambda (x) t)); which Clojure function are you thinking of?

kbp··on What Made Lisp Different (2002)
> ASDF appears to have been deprecated in favor of Quicklisp

No, ASDF and Quicklisp do different things. ASDF handles compiling and loading systems, whereas Quicklisp handles downloading systems and their dependencies. ASDF is kind of like make, and Quicklisp is kind of like a package manager.

kbp··on What Made Lisp Different (2002)
> Haskell functions are not Lisp functions. Lisp functions take a list of arguments, so `apply` should apply to a list of argument.

I understand how currying works, thanks, but that doesn't change the fact that $ is not equivalent to apply. A version of apply that dealt with curried functions would just have to fold over a list, and I don't think it could be properly generalised in Haskell's type system (but I"m not an expert at Haskell).

For your definition of apply, Lisp-1's don't have it, because as you said, you'd just call the damn function. Lisp-2's sort of have it, but it's called funcall. Regardless, your definition of apply is not what apply is in Lisp.

kbp··on Just what does “code as data” mean anyway? (2014)
> The closest thing to MacLisp today is actually Common Lisp

I think you could make the argument that Emacs Lisp is as close. Emacs Lisp has some major similarities with Maclisp that CL doesn't share (like in variable scoping and obarrays and such). Elisp and CL are both very close relatives of Maclisp; Elisp was designed as a mini-Maclisp for a text editor, whereas Common Lisp was designed as Maclisp's successor.

kbp··on Working remotely, 4 years in
> overzealous pedantry

Some people might consider it pedantic to insist to someone who was confused by a choice of wording, and offered a less potentially confusing alternative, that actually it's fine because it's technically correct, regardless of how people understand it when they read it.

kbp··on Working remotely, 4 years in
Sorry, I just edited in a second quote to my previous comment that addresses that part of your point.
← PreviousPage 6 of 12Next →