Import Upstream version 20180207
[hcoop/debian/mlton.git] / doc / guide / src / ReturnStatement.adoc
CommitLineData
7f918cf1
CE
1ReturnStatement
2===============
3
4Programmers coming from languages that have a `return` statement, such
5as C, Java, and Python, often ask how one can translate functions that
6return early into SML. This page briefly describes a number of ways
7to translate uses of `return` to SML.
8
9== Conditional iterator function ==
10
11A conditional iterator function, such as
12http://www.standardml.org/Basis/list.html#SIG:LIST.find:VAL[`List.find`],
13http://www.standardml.org/Basis/list.html#SIG:LIST.exists:VAL[`List.exists`],
14or
15http://www.standardml.org/Basis/list.html#SIG:LIST.all:VAL[`List.all`]
16is probably what you want in most cases. Unfortunately, it might be
17the case that the particular conditional iteration pattern that you
18want isn't provided for your data structure. Usually the best
19alternative in such a case is to implement the desired iteration
20pattern as a higher-order function. For example, to implement a
21`find` function for arrays (which already exists as
22http://www.standardml.org/Basis/array.html#SIG:ARRAY.findi:VAL[`Array.find`])
23one could write
24
25[source,sml]
26----
27fun find predicate array = let
28 fun loop i =
29 if i = Array.length array then
30 NONE
31 else if predicate (Array.sub (array, i)) then
32 SOME (Array.sub (array, i))
33 else
34 loop (i+1)
35in
36 loop 0
37end
38----
39
40Of course, this technique, while probably the most common case in
41practice, applies only if you are essentially iterating over some data
42structure.
43
44== Escape handler ==
45
46Probably the most direct way to translate code using `return`
47statements is to basically implement `return` using exception
48handling. The mechanism can be packaged into a reusable module with
49the signature
50(<!ViewGitFile(mltonlib,master,com/ssh/extended-basis/unstable/public/control/exit.sig)>):
51[source,sml]
52----
53sys::[./bin/InclGitFile.py mltonlib master com/ssh/extended-basis/unstable/public/control/exit.sig 6:]
54----
55
56(<!Cite(HarperEtAl93, Typing First-Class Continuations in ML)>
57discusses the typing of a related construct.) The implementation
58(<!ViewGitFile(mltonlib,master,com/ssh/extended-basis/unstable/detail/control/exit.sml)>)
59is straightforward:
60[source,sml]
61----
62sys::[./bin/InclGitFile.py mltonlib master com/ssh/extended-basis/unstable/detail/control/exit.sml 6:]
63----
64
65Here is an example of how one could implement a `find` function given
66an `app` function:
67[source,sml]
68----
69fun appToFind (app : ('a -> unit) -> 'b -> unit)
70 (predicate : 'a -> bool)
71 (data : 'b) =
72 Exit.call
73 (fn return =>
74 (app (fn x =>
75 if predicate x then
76 return (SOME x)
77 else
78 ())
79 data
80 ; NONE))
81----
82
83In the above, as soon as the expression `predicate x` evaluates to
84`true` the `app` invocation is terminated.
85
86
87== Continuation-passing Style (CPS) ==
88
89A general way to implement complex control patterns is to use
90http://en.wikipedia.org/wiki/Continuation-passing_style[CPS]. In CPS,
91instead of returning normally, functions invoke a function passed as
92an argument. In general, multiple continuation functions may be
93passed as arguments and the ordinary return continuation may also be
94used. As an example, here is a function that finds the leftmost
95element of a binary tree satisfying a given predicate:
96[source,sml]
97----
98datatype 'a tree = LEAF | BRANCH of 'a tree * 'a * 'a tree
99
100fun find predicate = let
101 fun recurse continue =
102 fn LEAF =>
103 continue ()
104 | BRANCH (lhs, elem, rhs) =>
105 recurse
106 (fn () =>
107 if predicate elem then
108 SOME elem
109 else
110 recurse continue rhs)
111 lhs
112in
113 recurse (fn () => NONE)
114end
115----
116
117Note that the above function returns as soon as the leftmost element
118satisfying the predicate is found.