A case against currying

Distinctions: Currying vs Tuples vs Parameter Lists

  • Several commenters argue all three are isomorphic in theory, but many languages treat parameter lists and tuples as distinct constructs (you can’t just pass a tuple where a parameter list is expected).
  • Some see value in treating all functions as single-argument over tuples (cleaner theory, simpler interpreters). Others prefer explicit multi-arg parameter lists for ergonomics and features like named arguments and defaults.
  • There’s debate over whether this third distinction (tuples vs parameter lists) is meaningful or mostly syntactic/ergonomic.

Ergonomics, Readability, and Errors

  • Critics of currying emphasize:
    • Ambiguity at call sites: f a b might be a value or a partially-applied function; you must know the arity from the type.
    • Missing-argument bugs: (f 1 2) instead of (f 1 2 3) silently yields a function; errors surface later and far away.
    • Harder-to-read code in large codebases, especially for newcomers.
  • Supporters value:
    • Concise pipelines and composition without lambdas (e.g., x |> f a b |> g c d).
    • Pointfree style and smoother equational reasoning.
  • Several people favor explicit partial-application syntax (placeholder “holes” like _, $, %, or it) as clearer than implicit currying, while still ergonomic.

Named Arguments and Business Code

  • Some argue named parameters are generally better in “business” code, reducing positional mistakes.
  • Counterpoints: redundancy when variable names already match parameter names, and friction when domain-specific names differ; features like name elision and “field punning” help but don’t fully resolve the tension.

Performance and Implementation

  • Concerns: extra allocations for tuple-passing, and overhead of currying for every call.
  • Others respond that compilers can and do optimize these patterns heavily; performance downsides are often overstated.

Language Design Experiences

  • Coalton recently removed currying in favor of fixed-arity functions, citing clearer type errors and simplicity.
  • Roc and some others reach similar conclusions: make currying/partial application explicit, not the default.
  • Standard ML and some Scheme/Lisp dialects are cited as examples of tuple-based or explicit-partial-application approaches.
  • Haskell/OCaml users report both powerful abstractions from currying and real-world pain from confusing types and error messages.