HNHacker News
TopNewBestAskShowJobs

kbp

807 karma · joined October 19, 2016

submissionscomments
kbp··on A new version of Common-Lisp.net has been launched
Do you have an example of where this would be a problem for you? What can't you represent?
kbp··on A Year in Clojure
I remember finding it pretty revelatory the first time I saw LET defined as a macro like

    (defmacro let (bindings &body body)
      `((lambda ,(mapcar #'first bindings) ,@body)
        ,@(mapcar #'second bindings)))
Seeing it use MAPCAR like that just made something click for me for whatever reason.
kbp··on Upgrading GitHub from Rails 3.2 to 5.2
I guess it's useful for deriving a baseline level of confidence, like a low coverage score is a red flag, and an increasing coverage score probably corresponds to increasing test coverage, but my issue is that 100% coverage doesn't mean anything about the correctness of the code in absolute terms (unless 'gaming the metric' includes not thinking of every edge case, ie, that we're assuming the existing test suite is perfect). If you're working on a poorly tested codebase, it's a useful relative metric of your progress in testing what already exists, but unless you're assuming the code is already correct, that doesn't mean anything more than that. If you wanted to derive, say, the confidence that you won't see 500's daily in production from a metric, then line coverage isn't an effective one to use for that; the tests you write that give you that kind of confidence don't really help your coverage score. The parts of the codebase that are in the most urgent need of tests for getting that kind of confidence in places will most of the time be ones that already have good coverage; think of how TDD works, even if you're not doing TDD.

I could agree that a high coverage score is a prerequisite for having confidence that your test suite is comprehensive (in general), but that's such a low bar, it's like saying a full bath is a prerequisite for a nice house, just knowing that shouldn't do much to convince you it's a mansion.

kbp··on Stop writing lambda expressions in Python
It used to, though. From the original Scheme paper: Note that in SCHEME, unlike MacLISP, the body of a LAMBDA expression is not an implicit PROGN.
kbp··on Upgrading GitHub from Rails 3.2 to 5.2
It's not about gaming the metric, it's just that the metric doesn't mean very much in the first place. Running a coverage tool during tests won't show you edge cases you forgot to handle in the code under test, it will show you code that's not tested at all. That can sometimes be useful for pointing out blind spots, but you shouldn't derive any confidence in the tests from a high coverage score, even if the people who worked on the project had the best intentions.

Coverage tools could only measure quality of a test suite if you're assuming that either the code is perfect or that the existing tests cover (logically) everything about what they test. Without either of those guarantees, it doesn't tell you anything very meaningful, as you discovered.

kbp··on JavaScript Equality Minesweeper
I can see what you're saying, but I think that argument would be a lot stronger if == compiled to ===. If you want an operator with ==='s semantics, it's there; providing == and claiming it behaves like === just seems like an opportunity for annoying surprises if something slips through the cracks. Since == doesn't compile to ===, I wouldn't use it unless I understood its semantics and wanted them.
kbp··on JavaScript Equality Minesweeper
I prefer it when Typescript tries to provide static type checking for Javascript rather than providing checking for how they wish Javascript was. `(x: number, y: string) => x == y` is an error because 'this condition will always return false'. In what language? There are linter rules for enforcing === over ==; Typescript having incorrect type definitions to try and make sure you only use == like === seems like a really poor solution to that.
kbp··on Introduction to Functional Programming in OCaml
> I think you're right that if FP is a trap at one end of the fallacy, pure OOP exists at the other.

I disagree; what spectrum are those on opposite ends of? Encapsulation, polymorphism, and inheritance are entirely compatible with FP, and immutability is entirely compatible with OOP. Functions and objects are equivalent. Most mainstream OO culture is centred around procedural programming, but it's the procedural parts that oppose a functional style, not the OO parts.

kbp··on Are “jets” a good idea? (2017)
Syntactically, those are things that could have been implemented as operators, but aren't, they're just LOOP keywords; lots of functions take keyword arguments (edit: even if LOOP's are a little different from &key parameters). LOOP avoids using unquoted lists for things other than calling operators.

edit: Oh, right, destructuring, too! I guess that also counts.

Out of curiosity, how would you feel about a macro like this (ignoring that it doesn't enforce any keyword order)?

    (defmacro for (var &key = (then =) while do)
      `(do ((,var ,= ,then))
           ((not ,while))
         ,do))
kbp··on Are “jets” a good idea? (2017)
> I can't imagine that most folks are surprised by the general shape of most defun statements.

The general shape of a LOOP expression is just a list of symbols and lists. A complicated LOOP expression that uses many features at once doesn't end up looking very Lispy, but a shorter one like (loop :repeat 10 :do (print 'hello)) shouldn't look at all foreign, especially if you write the keywords as keywords, which many people do.

I guess when people talk about the regularity of Lisp syntax, I think they usually mean that (op ...args) applies the operator OP to the list ARGS. LOOP obeys this very well: the only LOOP syntax I can think of that breaks it is `using (hash-key k)` or with HASH-VALUE. Universally accepted macros break this rule all the time, though. By shoving everything into lists, they totally abandon trying to keep with the (op ...args) form. If you see that regularity as a great advantage of Lisp's, then it seems like you should be much more bothered by the more "mundane" macros than you should be by LOOP.

    (loop :for i :below 10 :do (print i))
Is less "syntax-breaking" than:

    (dotimes (i 10) (print i))
kbp··on Are “jets” a good idea? (2017)
> My point was more on the rarity of "syntax breaking" macros.

Why don't you consider macros like DEFUN, DEFCLASS, COND, etc to be "syntax breaking"?

kbp··on The REPL for Hardware
That's some Lisp code; if you enter it at a REPL, it prints the result of evaluating it:

    CL-USER> (defun add (a b) (+ a b))
    ADD
kbp··on The Egison Programming Language
Sure, there's other ways to write it, the point of the post was Lisp's syntax, not the algorithm I used to demonstrate some features of it. You could write examples like yours in Lisp or Python, too. As well, your examples both slurp the whole file into memory, which mine avoided.

edit: And your C# version is only 24 non-whitespace characters shorter than the Python version, and 20 of those are because you called your variables 'f' instead of 'filespec' and 'w' instead of 'word'. A 4 non-whitespace character difference makes it exceedingly long and verbose? Or are you just advocating 1-letter variable names and avoiding newlines?

kbp··on The Egison Programming Language
> LISP doesn't really have syntax - you write parse trees directly.

Lisp has plenty of syntax, it's just extensible and largely defined in operators. Commonly used macros like DEFUN, WITH-OPEN-FILE, and LOOP all add their own syntax to the language; that's what macros are for. When you put them together, typical Lisp code ends up looking like

    (defun count-words (filespec)
      (with-open-file (f filespec)
        (loop with counts = (make-hash-table :test 'equal)
              for line = (read-line f nil)
              while line do
                (loop for word in (cl-ppcre:split "\\s+" line) do
                  (incf (gethash word counts 0)))
              finally (return counts))))
Which I don't think is that alien. It translates pretty cleanly into Python:

    def count_words(filespec):
        with open(filespec) as f:
            counts = collections.defaultdict(int)
            for line in f:
                for word in line.split():
                    counts[word] += 1
            return counts
Do you find the former significantly harder to understand? I don't see how it's any more like "writing a parse tree directly."

> Why should I write (+ p 2) when most people think (p+2)? This difference gets worse with more complex expressions.

As mentioned in other comments, there are infix packages available for when you're writing math-heavy code (or if you just need infix operators), but I also think that a lot of people don't write very much code with complicated inline arithmetic in it, and overstate how much the awkward math syntax would affect them (there are of course plenty of projects that are math-heavy and where it does make a large difference). When you're defining variables/functions/classes/etc or calling functions or looping or whatever, there's not much difference between Lisp and most other languages aside from whether the bracket is { or ( and which side of the keyword it goes on; in my experience, that sort of code tends to make up the large bulk of most codebases in most languages.

edit: Another place where Lisp's default syntax is significantly different from a lot of languages is something like object.f(x).g(y).h(z), which in Lisp looks like (h (g (f object x) y) z). This can be remedied with common macros like -> that let you write (-> object (f x) (g y) (h z)).

kbp··on Unix system programming in OCaml (2014)
> C has all these different kinds of control flow and all these built-in operators, whereas everything you would want to do in OCaml is just plain old functions and expressions.

OCaml does have for and while loops, to be fair, although they don't support break or continue (you can simulate break by throwing in the loop body).

kbp··on What a Russian Smile Means
I'd say that depends a lot on who you're talking to. I would answer like that to a close friend, but for most people I know I'd never answer more negatively than something like "eh, kinda stressed, but it's ok", and for a complete stranger (like krzyk mentioned) I would only ever say "fine" or a synonym.
kbp··on Pointers Are More Abstract Than You Might Expect in C
Right, that's what I was explaining. A lot of people get tripped up by this because arr is equivalent to &arr, int arr[] is equivalent to int *arr as a formal parameter, etc, so many people go around with the idea that arrays are just pointers in C, like in the comment I quoted; it's an easy thing to get confused by. I was giving an example to demonstrate how they differ.
kbp··on Pointers Are More Abstract Than You Might Expect in C
> I always thought [] was just syntactic sugar over a regular pointer, but seems like I was wrong.

For another example showing their differences, if a.c has:

    int n[] = { 1 };
And b.c has:

    extern int *n;
    printf("%d\n", *n);
Then running b.c will segfault, whereas if it said extern int n[], it would work as expected (hint: extern int n and printf("%d\n", n) would also work). Arrays degrade to pointers at the drop of a hat, but they're distinct from them.
kbp··on A Note from Cecil Adams about the Straight Dope
> The Straight Dope from Cecil Adams is like lots of that neat content that was essentially the internet before the internet.

You start with this, and then go into more examples of "content that was essentially the internet before the internet" like going to 7/11 with friends, reading Nintendo Power, and riding your bike. That sounds a lot more like missing your childhood than any cultural changes, especially when your pre-internet internet includes things like IRC and message boards. It seems like you're just using "internet" as a synonym for "the present".

> All of that greatness is turning to vaporwave nostalgia.

The only criteria for being included in "that greatness" is that you enjoyed it and it's not popular anymore: it isn't turning to nostalgia, it's nostalgia by definition.

Replace Cecil Adams and the Straight Dope with whatever you like, and this is just as fitting of a sappy eulogy.

kbp··on Python 3 at Facebook
> I never failed any take home assignments, so this isn't about me. I am speaking more generally and not about me personally.

It was generic "you", the hypothetical person who was having trouble with take home assignments but not interview questions that you were talking about initially. All of my points were about that hypothetical person, and not you personally. Sorry for the misunderstanding.

> My point is fundamentals don't change, frameworks do.

Yes, that's what I was addressing. Companies aren't asking about frameworks when they give you a take home question, they're asking you to learn the framework if need be, which will be easy if you know the fundamentals. I'm not sure where you're getting lost on this point.

kbp··on Python 3 at Facebook
> companies may discriminate against those candidates because they lack that industry specific skills (that otherwise could easily be picked up).

What does "otherwise" mean, here? The context we were discussing is that they asked you to quickly pick it up in a take-home assignment, and you couldn't pick it up that quickly. I don't see how this is them being shortsighted; it sounds like you just not delivering on the promise of your "fundamentals".

> the tooling or frameworks change but the core theory does not.

I 100% agree: someone who learnt MVC with Smalltalk in 1979 won't have any trouble picking up Rails' or Django's or whatever's version today. The concepts are timeless.

edit: to boil it down:

> these people should be able to pick up whatever tooling or frameworks on the job.

Yes, and if they can, they won't have trouble picking it up in the process of writing a take-home assignment. If they can't do that, then they just failed a litmus test.

kbp··on Python 3 at Facebook
> Companies I've seen don't care if you have fundamental knowledge of algorithms and data structures. They are testing you on specific frameworks via interview questions and take home projects

No, I got that. My point was that no one cares that you completed an algorithms and data structures course, they care that you know the fundamentals of (the subgenre they're interested in of) software development. You're just using a definiton of "fundamentals" that excludes the (entirely language and framework independent) concepts they care about that you don't know.

A take home project using a specific language and framework does not require you to know either to complete it before you start; if you know the concepts, you can pick them up as you're writing it. If you've never seen MVC before (and the knowledge you have doesn't allow you to grok it fast), then in a web dev context I would argue that that is a fundamental concept you are missing, which was my point.

Interview questions can be different, but you didn't mention them in the post I responded to.

kbp··on Python 3 at Facebook
> But unfortunately my experience is industry tends to not agree with us. They are like 'cool you know fundamentals, now do this take home project that requires x programming language with m framework'. This isn't too nice for new hires that learn just fundamentals and not the tooling and frameworks industry expects new grads to have.

I think the idea is that you should be able to pick up the language and framework as you go, if you do actually have the concepts down. If your generalised knowledge isn't to the point where you can apply it to some arbitrary framework/codebase in some arbitrary (imperative) language and start being productive more or less immediately (with documentation open in another tab), then your generalised knowledge just isn't at the level where people care about it, yet.

edit: That generalised knowledge they're expecting absolutely might go beyond what you're shown in school (it depends on the school). If you draw the line of "fundamentals" at "what was in my curriculum", then that's an arbitrary line you're drawing, and it's not the line that most of the industry is using (even if people are using their own coursework as their meter). If you consider (eg, in a web dev context) HTTP requests and MVC "fundamental", then you should be able to pick up Rails or Django or whatever without much trouble. Whether or not your school had classes on that doesn't really matter to anyone.

kbp··on JavaScript: Does It Mutate?
Somewhat relatedly, a very common mistake in Lisp is modifying literals; a lot of people don't realise that there's a difference between writing '(a b c) and writing (list 'a 'b 'c), but QUOTE's description in the spec plainly says "The consequences are undefined if literal objects (including quoted objects) are destructively modified." To demonstrate the difference in practice (DELETE is the destructive version of REMOVE):

    CL-USER> (defun abc-without (letter) (delete letter '(a b c)))
    ABC-WITHOUT
    CL-USER> (abc-without 'a)
    (B C)
    CL-USER> (abc-without 'b)
    (A C)
    CL-USER> (abc-without 'c)
    (A)
This behaves strangely because it modifies the constant list (A B C) rather than consing up a new one on each invocation (like calling LIST or COPY-SEQ would), so by the end the list it passes to DELETE has been reduced to (A).
kbp··on Console.table()
This is a useful trick, but I don't see how it addresses the issue they talked about. As I understand it, they were saying that Firefox and Chrome's Javascript REPL's scroll up through expressions rather than lines. If you say "const f = () => {" and press enter, it doesn't submit it until you close that brace, and when you use the up arrow to scroll back to it later, you get the whole thing (newlines preserved) instead of single lines of it.
kbp··on AI winter is well on its way
> AI winter is not "on its way". There is AI hype and anti-AI hype, and then there is actual practice. This article is anti-AI hype, just as bad as its opposite. In practice there are tons of useful applications.

I don't think the article was saying that AI isn't useful, but just that deep learning specifically is not an AI panacea, and that the current hype around AI is on its way out. The hype dying down and the associated buzzwords starting to repel money instead of attract it is all that's meant by AI winter, I believe, not that we'll run out of places where the techniques would be useful.

kbp··on I wrote a negative Yelp review and it made my life a nightmare
The longterm difference seems pretty minimal to me: they google his name and see reviews accusing him of fraud or they google his name and see tabloid articles about this story that say the same thing the reviews did, but add that the person making the accusations was sued for libel, alongside followup reports that the court decided the woman was lying. In the second case, the bad reports jump out more, but they're accompanied with notes that a court decided they were false, whereas with your Yelp responses the doctor wasn't even denying them. I don't think your approach is obviously better for the doctor when someone's looking up reviews of him in 5 years.
kbp··on I wrote a negative Yelp review and it made my life a nightmare
> Leave a single note, "We're sorry this patient wasn't satisfied with our service, and have refunded all fees. Since most of our patients are happy, we rarely need to do this." [0] Actually even that note is too confrontational

She accused him of committing felonious fraud; seeing the doctor respond by giving her her money back and saying "most people don't have a problem" would not cast that doctor in a good light at all, to me. I'm not really sure if there's any kind of response they could have left that would feel reassuring to me: recommending the client contact law enforcement like someone else suggested might help a little, but not that much. The presence of a review with accusations like that that the doctor shrugged off or dealt with casually would be infinitely more offputting to me than hearing the doctor had previously won a libel case against a former client.

kbp··on The Power of Prolog
> Or, as an old adage goes, "If it compiles, it works."

This isn't said about the declarative nature of languages so much as it is about the benefits of powerful static type systems, in my experience.

It's quite easy to write Prolog programs that look right (to me, someone who doesn't know Prolog well) but that compile, successfully run to completion, and produce incorrect results (or don't terminate). In Haskell, the compiler actually rejects a huge amount of incorrect programs that I thought were going to work (and the fact that I thought that shows that the declarative nature of the code wasn't sufficient) and then once the typechecker is finally happy, the code often does actually work without further debugging (this is a common experience, and what the saying is referring to, I believe); in Prolog (or dynamically typed functional languages like Scheme), there's very little of that, and I'm left to catch most bugs on my own (even if like you said there won't be as many because they'd be so obvious in the first place).

Prolog might be exceedingly clear once you learn how to read it and it might eliminate errors that way, but "if it compiles, it works" is a terrible description of that. "If it looks right to someone who knows the language well, it works" is much closer, but not as punchy. The entire point of the original saying is that you don't need the experience with the language to get that, because the compiler itself will tell you if you're wrong when your types won't line up.

kbp··on The Power of Prolog
> and even Scheme is 'the ultimate imperative' https://dspace.mit.edu/handle/1721.1/5790 !

Scheme isn't, lambda is. That paper is about how lexical closures alone are enough to simulate a lot of imperative concepts like assignment, loops, and gotos (they do cheat and use set! in a couple places, but the point of the paper is how much lambda application can do all on its own). Your broader point about Lisps not being particularly functionally oriented is correct, though; they're some of the most unopinionated languages you could imagine.

← PreviousPage 4 of 12Next →