HNHacker News
TopNewBestAskShowJobs

kbp

807 karma · joined October 19, 2016

submissionscomments
kbp··on The Origin of CAR and CDR in Lisp (2005)
> Left and Right are really commonly used in this situation in ML-descended languages. It’s not the worst thing.

Are you talking about Either types? OCaml and Haskell at least both call car and cdr fst and snd respectively, but they're rarely used.

As for left and right as names, I don't think they're any worse than car and cdr, I just don't think they're substantially better.

kbp··on The Origin of CAR and CDR in Lisp (2005)
> > When Rich Hickey invented Clojure, he kept the gems of the LISP tradition, but jettison much of the muck. This is why Clojure has first instead of car and rest instead of cdr

> Rich Hickey did not invent 'first' and 'rest'.

Rather than the names 'car' and 'cdr', the "muck" that Rich Hickey jettisoned here was conses as a core language feature. Since Lisp already used first and rest for operating on lists, Clojure borrowed those names, and since Clojure doesn't have conses (in the Lisp sense of the term; Clojure has a cons function, but it just adds elements to sequences rather than constructing pairs), it didn't have any need for car and cdr, which operate on conses.

It reminds me of a section from Kent Pitman's article 'More Than Words, or: Lambda, the Ultimate Political Party':

> Some years ago, when I was first becoming involved with language standards, I did a personal study of languages in the Lisp family to determine whether there was a common core of operators that were present throughout the family with the same name and semantics.

Then after going through several basic operators which differ in behaviour or name across dialects, he concludes:

> I did find that CONS was present in every Lisp I looked at with pretty much the same meaning, but that seemed to be an isolated case

kbp··on The Origin of CAR and CDR in Lisp (2005)
> So why stick with the names of 704 registers? Was there a purpose to this?

Are there other, much better names for the two parts of a pair? First and second aren't great because they're not clear that it's a pair and not a larger sequence (and the difference is important in Lisp; since lists are built on conses, it would be odd to get the tail of a list by calling 'second'). The only other names I can think of would be something like left and right, but I don't think those would be substantially easier to understand for beginners than car and cdr.

When working with lists, many people prefer to use the functions first and rest, which behave identically to car and cdr but are more meaningfully named for list applications. They would be terrible names for the general cons-handling functions, though.

kbp··on Introducing Duolingo Stories (Beta)
Stories are currently only available for English speakers learning French, German, Portuguese, and Spanish, but I think they're a really well-done kind of stepping stone from the regular Duolingo courses into a bit more in-context learning. Hopefully they'll keep fleshing it out; it's a really nice addition to their platform.
kbp··on Opinions on functional programming and OCaml
> In Python it isn't implicit, but it's still shared state, and so still hard to test and maintain. You can't test the `f` in your example without having to pass in the whole big bundle of state that self tends to be, even if you do so explicitly.

cies said structs were ok, what's the difference in this regard? 'Shared state' doesn't usually refer to explicitly passing a data structure into a function as an argument; it's operating on shared state only in the same way that any function which takes for example a string or a hash does.

kbp··on Opinions on functional programming and OCaml
> `class` has `self`, which is some kind of implicitly shared state that will bite you (harder to reason about, test and maintain).

For reasoning about and maintaining, you can just think of `self` as an extra parameter to the function that gets bound to the thing to the left of the dot. In some languages, like Python, this is how it actually works, so the testing argument doesn't apply either:

    >>> class C:
    ...     def __init__(self, x):
    ...         self.x = x
    ...     def f(self):
    ...         print(self.x)
    ... 
    >>> c = C(3)
    >>> c.f
    <bound method C.f of <__main__.C object at 0x7fdb6b9b9240>>
    >>> c.f()
    3
    >>> C.f
    <function C.f at 0x7fdb6b9b1ea0>
    >>> C.f()
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: f() missing 1 required positional argument: 'self'
    >>> C.f(c)
    3
kbp··on What's in an Emacs Lambda?
> These expressions are (or at least should be) functions on syntactic forms - syntax transformers.

I don't really agree with this. Backquote is just shorthand for a bunch of consing that makes the end result more clear. Macros are one application where being able to sort of template lists is very useful, but they're not the only one. As well, I think the tendency for people to learn backquote as a companion to defmacro tends to confuse people about how defmacro works.

kbp··on Learning Smalltalk is not a waste of time
Algol 68 is not the language most people mean when they say Algol, and was not a de facto standard language for publishing algorithms.
kbp··on Ask HN: Fully online CS degrees?
You can challenge courses at most schools if you already know the material.
kbp··on Lisp at the Frontier of Computation [video]
> Java had lists but no functional API on top of it. Processing ArrayLists is extremely different from (mapcar #'f '(....))

My point was that the functional API is the key difference, not arrays vs lists. Java in 2000 had lists and no functional API, whereas Lisp in 1970 had mutable arrays with a functional API available for use on them. Mapping over a list in Lisp looks like `(map 'list #'f '(...))` (The first argument is the return type; MAPCAR is just a list-specific version of MAP), mapping over a Java-style array looks like `(map 'list #'f #(...))`. Lists vs arrays makes no real difference (if they were in variables instead of literals, you couldn't even tell if it were an array or a list by looking at that call). Java in 2017 similarly has a functional API that can be used on lists or (much more commonly) on mutable arrays.

kbp··on Lisp at the Frontier of Computation [video]
It's from this: http://www-formal.stanford.edu/jmc/history/lisp/lisp.html
kbp··on Lisp at the Frontier of Computation [video]
> In non lisp languages, the mutable array often came without map / filter

What languages do you know that have map and filter for lists, but not for arrays? Lisp has them for both, C++ has them for both, Java has them for both; Java didn't used to have lambdas or map, but it had standard lists long before it got either of them. Several decades before Java existed, Lisp had mutable arrays with map and filter. Supporting higher order functions has nothing at all to do with arrays vs lists.

> didn't have lambdas so you end up writing imperative loops

Lisp does have lambdas and imperative loops are still extremely common in Lisp code.

kbp··on Lisp at the Frontier of Computation [video]
Yes, I agree. If you've ever read old Lisp code it's full of PROG and assigning variables and jumping around with gotos, McCarthy even said: "LISP also allows sequential programs written with assignment statements and go tos. Compared to the mathematically elegant recursive function definition features, the ``program feature'' looks like a hasty afterthought. This is not quite correct; the idea of having sequential programs in LISP antedates that of having recursive function definition." Mind, if you've ever read modern Lisp code, it's full of LOOP and ITER. Lisp has always been largely imperative.

As for what makes Lisp "different," I think it was true in about 1960 that it was mostly the functional support. It hasn't been for a long time, but I just think that people who don't know Lisp assuming that it is isn't completely unfounded.

> More, early lisps were far more up front about their imperative abstractions.

I will say that I have no idea how someone could look at Common Lisp and not realise it was largely an imperative language unless they had some major preconceptions going in.

kbp··on Lisp at the Frontier of Computation [video]
> map / filter over list is different from arrays.

How?

    CL-USER> (remove-if-not #'evenp '(1 2 3 4 5))
    (2 4)
    CL-USER> (remove-if-not #'evenp #(1 2 3 4 5))
    #(2 4)
    CL-USER> (loop for x in '(1 2 3 4 5) when (evenp x) do (format t "~&~a~%" x))
    2
    4
    NIL
    CL-USER> (loop for x across #(1 2 3 4 5) when (evenp x) do (format t "~&~a~%" x))
    2
    4
    NIL
Even a function like:

    (defun print-evens (sequence)
      (loop for i below (length sequence)
            for x = (elt sequence i)
            when (evenp x)
              do (format t "~&~a~%" x)))
Works for both, although it's considerably more efficient for arrays.

> Even in the 2000s we had to hand write Java Iterators and fear mutation while iterating .. that sort of things.

And even in Lisp, the standard specifies "The consequences are undefined when code executed during an object-traversing operation destructively modifies the object in a way that might affect the ongoing traversal operation."

kbp··on Lisp at the Frontier of Computation [video]
Around 60 years ago, Lisp pioneered functional programming and was the only thing that supported it at all. Up until the mid-90s or so it was still far and away the most popular language that had meaningful support for closures and higher order functions. That hasn't been true anymore for about 20 years, but for a long time anyone interested in using that stuff probably learnt it from Lisp, and Lisp was probably their best bet for getting to use it.

There was always more to Lisp (I read a cute essay from the mid-60s about how to balance assignment-and-goto style programming with recursive-pure-function style programming in Lisp), but older people making that connection isn't unreasonable, or younger people who've only heard older people talk about it.

kbp··on Lisp at the Frontier of Computation [video]
> Some checking also happens at compile time, even more if you intentionally include type declarations. (Type declarations are part of the ANSI Common Lisp standard.)

Just a note that this is entirely implementation-dependent. SBCL, for instance, is very good about using type declarations as correctness checks (those that can't be statically verified transparently degrade to runtime assertions) but their exact behaviour isn't specified in the standard; for example, implementations are free to take them as declarations that the programmer knows things the implementation doesn't and to trust them, which could cause weird bugs if they're not correct.

kbp··on Lisp at the Frontier of Computation [video]
> it's often highly interactive, and value oriented. You get to "touch" the data a bit like material. Nowadays repl's are common, so it doesn't seem special but it was so for 30years.

REPL's are common, but they're rarely as useful in other languages. Even relatively basic (to Lisp programmers) things are almost universally missing, for example:

    [1]> (defun f (x) (1+ (g x)))
    F
    [2]> (f 4)
    
    *** - EVAL: undefined function G
    The following restarts are available:
    USE-VALUE      :R1      Input a value to be used instead of (FDEFINITION 'G).
    RETRY          :R2      Retry
    STORE-VALUE    :R3      Input a new value for (FDEFINITION 'G).
    ABORT          :R4      Abort main loop
    Break 1 [3]> :r3
    New (FDEFINITION 'G)> (lambda (x) (* x 2))
    ;; Now that we gave an fdefinition for G, our (f 4) call can continue, so it
    ;; resumes execution and completes. Until now, it was just paused--no stack
    ;; unwinding unless we ask for it.
    9            
    [4]> (g 10)
    ;; Because we used STORE-VALUE, it went ahead and saved the value we gave in
    ;; G for future use. If we had used USE-VALUE, it would have finished the (f
    ;; 4) call using that definition, but G still wouldn't be fbound after.
    20
> lists mindset is different from mutable arrays

Mutable arrays are ubiquitous in Lisp. Explicitly cdring down lists is mostly only done in introductory textbooks; in practice, most people will use MAP, REDUCE, REMOVE-IF-NOT, etc instead, which all work just as well on arrays or lists, or they might use an imperative construct like DO, LOOP, or ITER (also note that conses are mutable as well; it's not at all unusual to setf a car or cdr or call NCONC). It's not terribly different from what you would do in eg modern Java (aside from the part where none of it requires special support from the implementation and it could all be implemented in user code).

I would also add that learning Lisp will teach you a lot about object-oriented programming. Even things that Java programmers use extensions for and give names like aspect-oriented programming just come built in as part of Lisp's stock object system. But then, Lisp's stock object system is also extremely flexible, especially given the pseudo-standard metaobject protocol. Quoting from Wikipedia about the MOP book:

"In his 1997 talk at OOPSLA, Alan Kay called [The Art of the Metaobject Protocol] "the best book anybody's written in ten years", and contended that it contained "some of the most profound insights, and the most practical insights about OOP", but was dismayed that it was written in a highly Lisp-centric and CLOS-specific fashion, calling it "a hard book for most people to read; if you don't know the Lisp culture, it's very hard to read"."

kbp··on Lisp at the Frontier of Computation [video]
Most Lisps have object systems; Common Lisp was the first ANSI-standardised language with one.
kbp··on Emacs for the HP49G
GNU Emacs wasn't the original Emacs, either (that was rms' PDP-10 editor built on top of TECO rather than Lisp), or even the original Lisp-based Emacs (that was Daniel Weinreb's EINE (EINE Is Not Emacs) which also had a successor ZWEI (ZWEI Was EINE Initially)). By the time GNU Emacs came out, Emacs was already a family of editors. GNU Emacs was made as a free software alternative to the first Emacs for Unix, Gosling Emacs (made by James Gosling, who later went on to design Java).

In a 1986 speech, rms discussed the beginnings of GNU Emacs:

"GNU Emacs is the main distributed portion of the GNU system. It's an extensible text editor a lot like the original emacs which I developed ten years ago, except that this one uses actual LISP as its extension language. [...] Gosling originally had set up his Emacs and distributed it free and gotten many people to help develop it, under the expectation based on Gosling's own words in his own manual that he was going to follow the same spirit that I started with the original Emacs. Then he stabbed everyone in the back by putting copyrights on it, making people promise not to redistribute it and then selling it to a software-house. My later dealings with him personally showed that he was every bit as cowardly and despicable as you would expect from that history.

"But in any case, my friend gave me this program, and my intention was to change the editing commands at the top level to make them compatible with the original Emacs that I was used to. But after a little bit of this, I discovered that the extension language of that editor, which is called MOCKLISP, was not sufficient for the task. I found that that I had to replace it immediately in order to do what I was planning to do. Before I had had the idea of someday perhaps replacing MOCKLISP with real LISP, but what I found out was that it had do be done first."

The full speech is really interesting: https://www.gnu.org/philosophy/stallman-kth.en.html

kbp··on Introduction to logic programming with Prolog
> You can write a quicksort in a few lines. You can traverse over a tree very easily. But understanding these few lines takes me more time than writing it in C, Java, PHP etc

I'm still only a beginner at Prolog, but that's what I enjoy about it: it's an entirely different way of tackling problems that really stretches my brain, not just new syntax on the same old paradigm that I already know.

kbp··on Introduction to logic programming with Prolog
It's always been interesting to me how Logo, a Lisp dialect, was so successful as a language for teaching children to program, but so many people still go around with the idea that Lisp is really hard to wrap your head around.
kbp··on Most popular Python packages now support Python 3
If you read the original Scheme report, you'll notice that it's full of example programs, zero of which run on modern Schemes. They're full of operators that Scheme doesn't have anymore, like BLOCK, PROGN, CATCH, ASET, -$, *$, //$, EVALUATE!UNINTERRUPTIBLY, START!PROCESS, etc.
kbp··on A CEO's Guide to Emacs (2015)
Even without paredit, Emacs has had forward-sexp, kill-sexp, etc, since the beginning.
kbp··on Perl and Undecidability (2008)
> Is it? (I honestly have no idea about Lisp.)

In Lisp you can modify the read table at run time, so you can do whatever you want. The functions the reader calls when it comes across '(', ')', ' ', and every other character are all completely customisable.

kbp··on Perl and Undecidability (2008)
> The decline of Perl's mindshare for new domains was totally separate from "sigils".

When you quoted someone saying "how Perl managed to become quite so profoundly disliked" and said "the conspicuous reasons seem to be a combination of: 1) PERL's usage of sigils," I took that to mean you were saying that sigils were a major reason that Perl isn't well-liked by as many people anymore. I'm sorry if that was a misunderstanding.

> Because special non-obvious symbols that "don't explain themselves" are perceived as terse.

The Merriam-Webster definition of 'terse' is 'using few words: devoid of superfluity.' It is not a synonym for noisy. 'my @list' is terser than 'List<T> list,' but both are wordier than better-liked-than-Perl languages like Python, Ruby, and Javascript, which is where Perl's mindshare went (I've been taking that last part as a given). I'm not claiming Perl isn't terse, I'm just saying that it was nonsensical to say that 'PERL's usage of sigils [...] makes code compact and terse.' Compared to C#, sure, but Perl was never competing with C#, and most of the mindshare it used to have didn't go to C#, so it's not really relevant. If the extra terseness (not noisiness) afforded by using sigils was a major reason for Perl's unpopularity, then Python, Ruby, and Javascript's popularity is very strange.

    print while (<>);
Is definitely terser than

    for line in fileinput.input():
        print(line)
But you'll notice there aren't even any sigils in the Perl version.

Sigils being ugly and Perl being too terse might both be problems it has, but they're different issues.

kbp··on Perl and Undecidability (2008)
> Yes, "$foo=7" is literally 1 character longer than "foo=7" which seems to violate terseness. (This is the example you seem to always gravitate back to.) For the 2nd time, I'm stressing that I already agree with that definition. However, that wasn't what I was talking about. People unfamiliar with a language that happens to have "ArrayList" spelled out is not as terse as "@".

I gravitate back to sigils because your point, that sigils' terseness contributed majorly to Perl's decline, was all I was objecting to. Python, Ruby, and Javascript don't spell out ArrayList either, yet those languages are now being used in most of the places where Perl used to be used. I ask again, if that was a major reason people left Perl, then why did the people who had that problem move to other languages that are even terser (ie, they don't spell out ArrayList and they don't even use sigils)?

kbp··on Perl and Undecidability (2008)
> Again, the "Perl lost to Python/Ruby ... terseness" connection is your narrative, not mine.

Well, if you just weren't considering Python and Ruby, then aren't they counter-examples to your point? They're terser than Perl in that regard; if that's a major reason people moved away from Perl, then why did so many of them move to those languages?

> I agree and I didn't say they were.

Then why did you bring them up in a discussion about sigils?

kbp··on Perl and Undecidability (2008)
> I also wasn't really focused on "@%$" specifically but you had brought it up

My involvement in this conversation started with quoting you saying that one of the major reasons for Perl becoming disliked was "PERL's usage of sigils.[1] One the one hand, it makes code compact and terse". Perl's use of sigils has nothing to do with terseness, and since Perl lost its mindshare to Ruby and Python which to the tiny extent that sigils contribute to terseness/verbosity are more terse, I don't think that's a valid point about Perl's trajectory.

> I get this weird feeling that I'm discussing with someone who's emotionally invested in Perl and he feels like I'm bashing Perl.

I don't even know Perl, I'm just critiquing your logic.

> Perl syntax such as "<>"

'<' and '>' are not used as sigils in Perl.

kbp··on Perl and Undecidability (2008)
My point was that the fact that C++ (like Perl) has had multiple updates in the past few years, and that Nvidia chose C++ instead of Perl as the primary language for an API are not evidence of Perl's decline. Perl 5 receives more frequent updates than C++, and C++ is being used where it makes sense and where Perl wouldn't have been used even when it was the new hotness. How is that evidence that Perl has fallen off?

I'm not saying that Perl's popularity hasn't greatly declined, I'm just saying that the evidence you're offering for it isn't evidence.

kbp··on Perl and Undecidability (2008)
> Yes, I understand that C++ does not compete with Perl. My point is the rejuvenation stories

Well, the way C++ had new versions released in 2017 and 2014, Perl 5 had new versions released in 2017 and 2016; what stagnation are you demonstrating? You said "updates to C++ via C++14 and C++17 were discussions that turned into reality"; and the same thing happened with updates to Perl 5 (which is the language "Perl" is usually shorthand for). Perl 6 is an entirely different language, it, along with languages like Ruby, compares to Perl 5 the same way C# and Rust compare to C++.

← PreviousPage 8 of 12Next →