Import Upstream version 20180207
[hcoop/debian/mlton.git] / doc / guide / src / OptionalArguments.adoc
1 OptionalArguments
2 =================
3
4 <:StandardML:Standard ML> does not have built-in support for optional
5 arguments. Nevertheless, using <:Fold:>, it is easy to define
6 functions that take optional arguments.
7
8 For example, suppose that we have the following definition of a
9 function `f`.
10
11 [source,sml]
12 ----
13 fun f (i, r, s) =
14 concat [Int.toString i, ", ", Real.toString r, ", ", s]
15 ----
16
17 Using the `OptionalArg` structure described below, we can define a
18 function `f'`, an optionalized version of `f`, that takes 0, 1, 2, or
19 3 arguments. Embedded within `f'` will be default values for `i`,
20 `r`, and `s`. If `f'` gets no arguments, then all the defaults are
21 used. If `f'` gets one argument, then that will be used for `i`. Two
22 arguments will be used for `i` and `r` respectively. Three arguments
23 will override all default values. Calls to `f'` will look like the
24 following.
25
26 [source,sml]
27 ----
28 f' $
29 f' `2 $
30 f' `2 `3.0 $
31 f' `2 `3.0 `"four" $
32 ----
33
34 The optional argument indicator, +&grave;+, is not special syntax ---
35 it is a normal SML value, defined in the `OptionalArg` structure
36 below.
37
38 Here is the definition of `f'` using the `OptionalArg` structure, in
39 particular, `OptionalArg.make` and `OptionalArg.D`.
40
41 [source,sml]
42 ----
43 val f' =
44 fn z =>
45 let open OptionalArg in
46 make (D 1) (D 2.0) (D "three") $
47 end (fn i & r & s => f (i, r, s))
48 z
49 ----
50
51 The definition of `f'` is eta expanded as with all uses of fold. A
52 call to `OptionalArg.make` is supplied with a variable number of
53 defaults (in this case, three), the end-of-arguments terminator, `$`,
54 and the function to run, taking its arguments as an n-ary
55 <:ProductType:product>. In this case, the function simply converts
56 the product to an ordinary tuple and calls `f`. Often, the function
57 body will simply be written directly.
58
59 In general, the definition of an optional-argument function looks like
60 the following.
61
62 [source,sml]
63 ----
64 val f =
65 fn z =>
66 let open OptionalArg in
67 make (D <default1>) (D <default2>) ... (D <defaultn>) $
68 end (fn x1 & x2 & ... & xn =>
69 <function code goes here>)
70 z
71 ----
72
73 Here is the definition of `OptionalArg`.
74
75 [source,sml]
76 ----
77 structure OptionalArg =
78 struct
79 val make =
80 fn z =>
81 Fold.fold
82 ((id, fn (f, x) => f x),
83 fn (d, r) => fn func =>
84 Fold.fold ((id, d ()), fn (f, d) =>
85 let
86 val d & () = r (id, f d)
87 in
88 func d
89 end))
90 z
91
92 fun D d = Fold.step0 (fn (f, r) =>
93 (fn ds => f (d & ds),
94 fn (f, a & b) => r (fn x => f a & x, b)))
95
96 val ` =
97 fn z =>
98 Fold.step1 (fn (x, (f, _ & d)) => (fn d => f (x & d), d))
99 z
100 end
101 ----
102
103 `OptionalArg.make` uses a nested fold. The first `fold` accumulates
104 the default values in a product, associated to the right, and a
105 reversal function that converts a product (of the same arity as the
106 number of defaults) from right associativity to left associativity.
107 The accumulated defaults are used by the second fold, which recurs
108 over the product, replacing the appropriate component as it encounters
109 optional arguments. The second fold also constructs a "fill"
110 function, `f`, that is used to reconstruct the product once the
111 end-of-arguments is reached. Finally, the finisher reconstructs the
112 product and uses the reversal function to convert the product from
113 right associative to left associative, at which point it is passed to
114 the user-supplied function.
115
116 Much of the complexity comes from the fact that while recurring over a
117 product from left to right, one wants it to be right-associative,
118 e.g., look like
119
120 [source,sml]
121 ----
122 a & (b & (c & d))
123 ----
124
125 but the user function in the end wants the product to be left
126 associative, so that the product argument pattern can be written
127 without parentheses (since `&` is left associative).
128
129
130 == Labelled optional arguments ==
131
132 In addition to the positional optional arguments described above, it
133 is sometimes useful to have labelled optional arguments. These allow
134 one to define a function, `f`, with defaults, say `a` and `b`. Then,
135 a caller of `f` can supply values for `a` and `b` by name. If no
136 value is supplied then the default is used.
137
138 Labelled optional arguments are a simple extension of
139 <:FunctionalRecordUpdate:> using post composition. Suppose, for
140 example, that one wants a function `f` with labelled optional
141 arguments `a` and `b` with default values `0` and `0.0` respectively.
142 If one has a functional-record-update function `updateAB` for records
143 with `a` and `b` fields, then one can define `f` in the following way.
144
145 [source,sml]
146 ----
147 val f =
148 fn z =>
149 Fold.post
150 (updateAB {a = 0, b = 0.0},
151 fn {a, b} => print (concat [Int.toString a, " ",
152 Real.toString b, "\n"]))
153 z
154 ----
155
156 The idea is that `f` is the post composition (using `Fold.post`) of
157 the actual code for the function with a functional-record updater that
158 starts with the defaults.
159
160 Here are some example calls to `f`.
161 [source,sml]
162 ----
163 val () = f $
164 val () = f (U#a 13) $
165 val () = f (U#a 13) (U#b 17.5) $
166 val () = f (U#b 17.5) (U#a 13) $
167 ----
168
169 Notice that a caller can supply neither of the arguments, either of
170 the arguments, or both of the arguments, and in either order. All
171 that matter is that the arguments be labelled correctly (and of the
172 right type, of course).
173
174 Here is another example.
175
176 [source,sml]
177 ----
178 val f =
179 fn z =>
180 Fold.post
181 (updateBCD {b = 0, c = 0.0, d = "<>"},
182 fn {b, c, d} =>
183 print (concat [Int.toString b, " ",
184 Real.toString c, " ",
185 d, "\n"]))
186 z
187 ----
188
189 Here are some example calls.
190
191 [source,sml]
192 ----
193 val () = f $
194 val () = f (U#d "goodbye") $
195 val () = f (U#d "hello") (U#b 17) (U#c 19.3) $
196 ----