Hacker Newsnew | past | comments | ask | show | jobs | submit | riwsky's commentslogin

The functional programming take is that “the result of foobinade-ing an and b” IS “foobinade applied to two of its arguments”. The application is not some syntactic pun or homonym that can refer to two different meanings—those are the same meaning.

Let us postulate two functions. One is named foobinade, and it takes three arguments. The other is named foobinadd, and it only takes two arguments. (Yes, I know, shoot anybody who actually names things that way.)

When someone writes

  f = foobinade a b
  g = foobinadd c d
there is no confusion to the compiler. The problem is the reader. Unless you have the signatures of foobinade and foobinadd memorized, you have no way to tell that f is a curried function and g is an actual result.

Whereas with explicit syntax, the parentheses say what the author thinks they're doing, and the compiler will yell at them if they get it wrong.


> Unless you have the signatures of foobinade and foobinadd memorized, you have no way to tell that f is a curried function and g is an actual result.

Yes, but the exact FP idea here is that this distinction is meaningless; that curried functions are "actual results". Or rather, you never have a result that isn't a function; `0` and `lambda: 0` (in Python syntax) are the same thing.

It does, of course, turn out that for many people this isn't a natural way of thinking about things.


> Yes, but the exact FP idea here is that this distinction is meaningless; that curried functions are "actual results".

Everyone knows that. At least everyone who would click a post titled "A case against currying." The article's author clearly knows that too.

That's not the point. The point is that this distinction is very meaningful in practice, as many functions are only meant to be used in one way. It's extremely rare that you need to (printf "%d %d" foo). The extra freedom provided by currying is useful, but it should be opt-in.

Just because two things are fundamentally equivalent, it doesn't mean it's useless to distinguish them. Mathematics is the art of giving the same name to different things; and engineering is the art of giving different names to the same thing depending on the context.


> It's extremely rare that

Not when a language embraces currying fully and then you find that it’s used all the fucking time.

It’s really simple as that: a language makes the currying syntax easy, and programmers use it all the time; a language disallows currying or makes the currying syntax unwieldy, and programmers avoid it.


> It's extremely rare that you need to (printf "%d %d" foo)

I write stuff like `map (printf "%d %d" m) ns` all the time. I daresay I even do the map as a partial application, so double currying.


But arguably your intent would be much more clear with something like `map (printf "%d %d" m _) ns` or a lambda.

I don't think parent is saying that partial application is bad, far from it. But to a reader it is valuable information whether it's partial or full application.


Not really when reading `iter (printf %"d %d" m) ns`, I am likely to read it in three steps

  - `iter`: this is a side-effect on a collection
  - `(printf`: ok, this is just printing, I don't care about what is printed, let's skip to the `)`
  - ns: ok, this is the collection being printed
Notice that having a lambda or a partial application `_` will only add noise here.

> But to a reader it is valuable information whether it's partial or full application.

This can be a valuable information in some context, but in a functional language, functions are values. Thus a "partial application" (in term of closure construction) might be better read as a full application because the main type of concern in the current context is a functional type.


Fine, it's a regular type. It's still not the type I think it is. If it's an Int -> Int when I think it's an Int, that's still a problem, no matter how much Int -> Int is an "actual result".

Come on, just write

    let f :: Int = foobinade a b
And the compiler immediately tells you that you are wrong: your type annotation does not unify with compiler’s inferred type.

And if you think this is verbose, well many traditional imperative languages like C have no type deduction and you will need to provide a type for every variable anyways.


I spent the last three years on the receiving end of mass quantities of code written by people who knew what they were writing but didn't do an adequate job of communicate it to readers who didn't already know everything.

What you say is true. And it works, if you're the author and are having trouble keeping it all straight. It doesn't work if the author didn't do it and you are the reader, though.

And that's the more common case, for two reasons. First, code is read more often than it's written. Second, when you're the author, you probably already have it in your head how many parameters foobinade takes when you call it, but when you're the reader, you have to go consult the definition to find out.

But if I was willing to do it, I could go through and annotate the variables like that, and have the compiler tell me everything I got wrong. It would be tedious, but I could do it.


Doesn’t that just imply that your tooling is inadequate? In LINQPad (and, I assume VS though I have done it in a while), when you hover over a “var” declaration a tooltip tells you the actual type the compiler inferred.

If 0 and a function that always returns 0 are the same thing, does that make `lambda: lambda: 0` also the same? I suppose it must do, otherwise `0` and `lambda: 0` were not truly the same.

In a non-strict language without side-effects, having a function with no arguments does not make sense. Haskell doesn't even let you do that.

You can write a function that takes a single throw-away argument (eg 0 vs \ () -> 0) and, while the two have some slight differences at runtime, they're so close in practice that you almost never write functions taking a () argument in Haskell. (Which is very different from OCaml!)


Another way to make the point: when you write 0, which do you mean?

In a pure language like Haskell, 0-ary functions <==> constants


Yes, and that becomes more intuitive when you "un-curry" the nested lambdas into a single lamba with twice the number of arguments. The point is that the state of a constant does not depend whatsoever on the state of the (rest of the) world, how much ever of that state piles on.

It’s not at all clear or the same to the new reader of the code.

Sure—but that’s a property of the inferred types moreso than the mere application syntax. It can be hard to revisit or understand the type of JS or unannotated Python expressions, too—but unlike those cases, the unknown-to-the-reader type of the Haskell code will always be known on the compiler/LSP side.

and a few weeks down the line authors also turn back into new readers...

I have a lot more long term memory than that.

cries in google wave


+1, google wave might have been the best thing Google ever made.


In fairness to the skill author, this is indeed what Elon did to the US government with DOGE


Am I the only one who finds this material rather dense?


1. The collaboration and notation app for rock bands that I’d wished existed already: https://bandwith.rocks/about

2. A “runtime scheduler for humans” that I wished existed, too (think morning routines, travel checklists, and pomodoros in the same abstraction—but also a lot of support for ad-hoc rearrangement and addition of the task queue).


I agree that the font and emoji hops aren’t great for complexity or performance, but the problem in the post was in the rendering of a tiny SVG; serving it directly would not have avoided the problem.


Damn, wait: you mean the random HN commenter didn’t magically solve a difficult problem that has long-confounded experts, simply by bringing their unique insights and thirty seconds to bear?


> What's missing is a widespread replacement for XSLT

jq says hello!


"I give it a hot minute before this type of task tracking lands in Claude Code."

aaaaand right on cue: https://github.com/anthropics/claude-code/commit/e431f5b4964... https://www.threads.com/@boris_cherny/post/DT15_k2juQH/at-th...


“I’m going to go lay down and, uh, think about the problem with my eyes closed”

Oh good, mainstream coders finally catching up with the productivity of 2010s Clojurists and their “Hammock Driven Development”! (https://m.youtube.com/watch?v=f84n5oFoZBc)


Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: