Consider a programming language whose syntax for function calls requires naming each passed argument, but as a benefit for this extra verbosity, allows specifying the arguments in any order:
f { foo = 3, bar = True, baz = "hello" }
If an argument is omitted, there are several things that could happen, depending on how the language is defined.
- Compile time error.
- It becomes a partial function application, a lambda function of the missing arguments. Haskell does this with currying when trailing arguments are omitted. (Tangentially, in Haskell, creating a lambda for a missing argument that is not the last one requires a little bit more work.)
- The missing arguments get silently assigned a lazy "undefined" value, which results in a run-time error if the "undefined" is ever evaluated.
- The language permits the function definition to provide default values to some omitted arguments. If there is no default value, then compile-time error. C++ does this.
It would be nice if a language could provide all of these options, even though strictly speaking they are mutually exclusive.
An imperfect solution is to have special keywords invoking #2, #3 and #4, perhaps something like f { foo = 3, REST UNDEFINED } or REST DEFAULT or REST LAMBDA, explicitly indicating indicating what do with the rest of arguments omitted at a call site.
I have seen default values implemented in Haskell using its typeclass mechanism, e.g., configuration values in xmonad. Default values are overridden using record modification syntax.
A hybrid between #1 and #4 would have the compiler always produce an error if arguments are missing, but indicate in the compile error that a default value is available via an explicit keyword (as above) when one is.
A list of named parameters and their values looks kind of like a record or struct. Make such a list a real type and allow variables of that type to be declared and assigned. A special syntax allows invoking a function with a record instead of a named argument list. If two functions have the same named parameters, are their parameter record types the same? Duck typing.
This scheme also gets messy when arguments may be omitted; we need to be able to define record types with only a subset of the parameters of a function, as well as possibly allowing REST UNDEFINED or REST DEFAULT as dynamic values in the record. If using REST LAMBDA, and whether a record field is defined is only known dynamically, then type checking and kind checking has to be postponed until run-time.
One of the things that makes me uneasy about Haskell record syntax is the following: REST UNDEFINED (#3) occurs implicitly when records are constructed whereas REST LAMBDA (#2) occurs when omitting trailing arguments when using positional constructors. The latter will usually cause a type checking error if the argument was omitted accidentally whereas the former waits for a run-time error.
Previously: Same idea.
Having to specify a function name as well as all its parameter names might become tedious for the programmer. Perhaps have mechanisms for a programmer to define alternate parameter names or omit a name. Vaguely related: by type.
1 comment :
These are interesting ideas. Haskell's type-level programming features actually seem mature enough to do this. In particular, ideas from the records package seem applicable.
Post a Comment