Hacker News new | ask | show | jobs
by calf 87 days ago
What's the steelman argument though? Why do languages like Haskell have currying? I feel like that is not set out clearly in the argument.
3 comments

I have a web backend with a top-level server that looks something like:

  ...

  :<|> collectionsServer compactor env registry
  :<|> queryServer qp sp struc registry warcFileReader logger
  :<|> indexationServer fetcher indexer

  ...
I.e. a request coming into the top-level server will go into the collections server or the query server or the indexation server. Each server is further broken down (collections has 4 routes, query has 4 routes, indexation has 5 routes.)

So lets try making the the arguments of just the collections server explicit. (It will take me too long to try to do them all.)

You can 'list' collections, 'delete' a collection, merge collectionA into collectionB, or get the directory where the collections live. So the input (the lambda term(s) we're trying to make explicit) can be () or (collectionName) or (collectionNameA, collectionNameB) or ().

In order to put these lambda terms explicitly into the source code, we need to add four places to put them, by replacing collectionsServer with the routes that it serves:

  ...

  :<|> (       listCollections registry
         :<|> (\collectionName -> deleteCollection env registry collectionName)
         :<|> (\collectionName1 collectionName2 -> mergeInto compactor collectionName1 collectionName2)
         :<|>  getCollectionDir env ) 
  :<|> queryServer qp sp struc registry warcFileReader logger
  :<|> indexationServer fetcher indexer

  ...
And now you know what explicit lambda terms collectionsServer takes!
The practical upside is that it makes using higher-order functions much smoother, with less distracting visual noise.

In Haskell this comes up all over the place. It's somewhat nice for "basic" cases (`map (encode UTF8) lines` vs `map (\ line -> encode UTF8 line) lines`) and, especially, for more involved examples with operators: `encode <$> readEncoding env <*> readStdin` vs, well, I don't even know what...)

You could replace the latter uses with some alternative or special syntax that covered the most common cases, like replacing monads with an effect system that used direct syntax, but that would be a lot less flexible and extensible. Libraries would not be able to define their own higher-order operations that did not fit into the effect system without incurring a lot of syntactic overhead, which would make higher-order abstractions and embedded DSLs much harder to use. The only way I can think of for recovering a similar level of expressiveness would be to have a good macro system. That might actually be a better alternative, but it has its own costs and downsides!

Mathematically it's quite pretty, and it gives you elegant partial application for free (at least if you want to partially apply the first N arguments).
Well, I disagree, you are, effectively, calling entire textbooks and CS sub disciplines merely "pretty", which is again the strawman I am referring to. This is like calling theoretical Turing award level advances mathematically pretty. I hope you see why that is problematic and biased framing.

More plausible is that Haskell designers recognized that Currying is a fundamental phenomenon of the lambda calculus so it needed some kind of primitive syntax for it. I'm not an expert but that is the most reasonable supposition for a rationale to start with. One can then argue if the syntax is good or not, but to do away with currying entirely is changing the premise of recognizing fundamental properties of Turing-complete functional programming language paradigms. It's not about prettiness, it's about the science.