Named optional function argument pattern

A lot of programming languages have named optional function arguments built-in as a language feature, like the **kwargs in Python. That’s a nice feature which sometimes really comes in handy, but it conflicts with other features. It’s difficult for a language to have

  1. named optional function arguments
  2. sound type inference
  3. partial function application

I can’t think of a language which does all three, but the language which comes closest is PureScript. There is a nice pattern for using the PureScript extensible record system to get named optional function arguments.

I first encountered this pattern in React.Basic.DOM, and I recently used it to write the new Parsing.String.regex function.

It’s a really useful pattern and I can’t find it documented anywhere except in this tweet from @hdgarrood .

So I’m going to copy Harry’s example into this post to make it more discoverable.

This goo function essentially has three named arguments: a, which is required, and x and y which are optional. If either x or y is not supplied then the default value is used. If the user tries to pass in an argument with a different name then it will fail to typecheck.

“We need a separate allFields type variable because it’s not the same as the AllFields synonym, in that it will have duplicate labels. That’s what the Nub constraint is for.”

import Prelude
import Prim.Row (class Union, class Nub)
import Type.Row (type (+))
import Record as Record

type OptionalFields r = ( x :: Int, y :: Int | r )
type RequiredFields = (a :: Int)
type AllFields = OptionalFields + RequiredFields

goo ::
  forall given allFields.
  Union given (OptionalFields ()) allFields =>
  Nub allFields AllFields =>
  Record given ->
  String
goo r = show m
  where
    m :: Record AllFields
    m = Record.merge r defaults
    defaults :: Record (OptionalFields ())
    defaults = { x: 2, y: 3 }
>>> goo { a: 3 }
"{ a: 3, x: 2, y: 3 }"
>>> goo { a: 1, y: 10 }
"{ a: 1, x: 2, y: 10 }"
>>> goo { a: 1, x: 9, y: 10 }
"{ a: 1, x: 9, y: 10 }"
3 Likes

For reference, there’s GitHub - natefaubion/purescript-convertable-options: Highly-overloaded APIs for PureScript which can take care of this.

5 Likes

It’s difficult for a language to have

  1. named optional function arguments
  2. sound type inference
  3. partial function application

I can’t think of a language which does all three, but the language which comes closest is PureScript.

OCaml? OCaml - Labeled arguments There are some caveats with respect to type inference, but I’d be surprised if it’s unsound.

4 Likes