A case against currying

Currying—treating every function as taking one argument and returning another function—is coming under renewed scrutiny in functional language design. Programmers weigh its theoretical elegance and convenient partial application against practical drawbacks like confusing type errors, ambiguous intent at call sites, performance concerns, and awkward ergonomics compared to tuple-style or parameter-list arguments, especially when named parameters or explicit “hole” syntax for partial application are available. Several newer or evolving languages are moving toward fixed-arity or tuple-based functions with explicit partial application, reflecting a broader shift from mathematical purity toward readability and maintainability in real-world codebases.

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.