Nested function: Difference between revisions
(added ocaml) |
(added sml) |
||
Line 135: | Line 135: | ||
let () = |
let () = |
||
print_string (make_list ". ") |
print_string (make_list ". ")</lang> |
||
</lang> |
|||
Interestingly, on my computer it prints the numbers in reverse order, probably because the order of evaluation of arguments (and thus order of access of the counter) is undetermined: |
Interestingly, on my computer it prints the numbers in reverse order, probably because the order of evaluation of arguments (and thus order of access of the counter) is undetermined: |
||
{{out}} |
{{out}} |
||
Line 202: | Line 201: | ||
(display (make-list ". "))</lang> |
(display (make-list ". "))</lang> |
||
=={{header|Standard ML}}== |
|||
<lang sml>fun make_list separator = |
|||
let |
|||
val counter = ref 1; |
|||
fun make_item item = |
|||
let |
|||
val result = Int.toString (!counter) ^ separator ^ item ^ "\n" |
|||
in |
|||
counter := !counter + 1; |
|||
result |
|||
end |
|||
in |
|||
make_item "first" ^ make_item "second" ^ make_item "third" |
|||
end; |
|||
print (make_list ". ")</lang> |
|||
=={{header|Swift}}== |
=={{header|Swift}}== |
Revision as of 03:33, 19 September 2016
In many languages, functions can be nested, resulting in outer functions and inner functions. The inner function can access variables from the outer function. In most languages, the inner function can also modify variables in the outer function.
The Task
Write a program consisting of two nested functions that prints the following text.
1. first 2. second 3. third
The outer function (called MakeList or equivalent) is responsible for creating the list as a whole and is given the separator ". " as argument. It also defines a counter variable to keep track of the item number. This demonstrates how the inner function can influence the variables in the outer function.
The inner function (called MakeItem or equivalent) is reponsible for creating one of the list items. It accesses the separator from the outer function and modifies the counter.
References:
ALGOL 68
<lang algol68>PROC make list = ( STRING separator )STRING:
BEGIN INT counter := 0; PROC make item = ( STRING item )STRING: BEGIN counter +:= 1; whole( counter, 0 ) + separator + item + REPR 10 END; # make item # make item( "first" ) + make item( "second" ) + make item( "third" ) END; # make list #
print( ( make list( ". " ) ) ) </lang>
C#
<lang csharp>string MakeList(string separator) {
var counter = 1;
var makeItem = new Func<string, string>((item) => { return counter++ + separator + item + "\n"; });
return makeItem("first") + makeItem("second") + makeItem("third");
}
Console.WriteLine(MakeList(". "));</lang>
J
J does not have nested scopes, so they must be emulated. (The design philosophy here is that nesting tends to become difficult to understand when taken too far, so the coder and designer should be mildly penalized with extra work for choosing nesting as opposed to some other problem solving approach.)
That said, emulating a single level of nesting is relatively trivial and does not reflect the complexities necessary for more elaborate (and more difficult to understand) cases:
<lang J>MakeList=: dyad define
sep_MakeList_=: x cnt_MakeList_=: 0 ;MakeItem each y
)
MakeItem=: verb define
cnt_MakeList_=: cnt_MakeList_+1 (":cnt_MakeList_),sep_MakeList_,y,LF
)</lang>
Example use:
<lang J> '. ' MakeList 'first';'second';'third' 1. first 2. second 3. third </lang>
JavaScript
<lang javascript>function makeList(separator) {
var counter = 1;
function makeItem(item) { return counter++ + separator + item + "\n"; }
return makeItem("first") + makeItem("second") + makeItem("third");
}
console.log(makeList(". "));</lang>
Lua
<lang lua>function makeList(separator)
local counter = 1
local function makeItem(item) return counter .. separator .. item .. "\n" end
return makeItem("first") .. makeItem("second") .. makeItem("third")
end
print(makeList(". "))</lang>
Objective-C
<lang objc>NSString *makeList(NSString *separator) {
__block int counter = 1; NSString *(^makeItem)(NSString *) = ^(NSString *item) { return [NSString stringWithFormat:@"%d%@%@\n", counter++, separator, item]; }; return [NSString stringWithFormat:@"%@%@%@", makeItem(@"first"), makeItem(@"second"), makeItem(@"third")];
}
int main() {
NSLog(@"%@", makeList(@". ")); return 0;
}</lang>
OCaml
<lang ocaml>let make_list separator =
let counter = ref 1 in
let make_item item = let result = string_of_int !counter ^ separator ^ item ^ "\n" in incr counter; result in
make_item "first" ^ make_item "second" ^ make_item "third"
let () =
print_string (make_list ". ")</lang>
Interestingly, on my computer it prints the numbers in reverse order, probably because the order of evaluation of arguments (and thus order of access of the counter) is undetermined:
- Output:
3. first 2. second 1. third
Perl
<lang perl>sub makeList {
my $separator = shift; my $counter = 1;
sub makeItem { $counter++ . $separator . shift . "\n" }
makeItem("first") . makeItem("second") . makeItem("third")
}
print makeList(". ");</lang>
PHP
<lang php><? function makeList($separator) {
$counter = 1;
$makeItem = function ($item) use ($separator, &$counter) { return $counter++ . $separator . $item . "\n"; };
return $makeItem("first") . $makeItem("second") . $makeItem("third");
}
echo makeList(". "); ?></lang>
Python
<lang python>def makeList(separator):
counter = 1
def makeItem(item): nonlocal counter result = str(counter) + separator + item + "\n" counter += 1 return result
return makeItem("first") + makeItem("second") + makeItem("third")
print(makeList(". "))</lang>
Scheme
<lang scheme>(define (make-list separator)
(define counter 1) (define (make-item item) (let ((result (string-append (number->string counter) separator item "\n"))) (set! counter (+ counter 1)) result)) (string-append (make-item "first") (make-item "second") (make-item "third")))
(display (make-list ". "))</lang>
Standard ML
<lang sml>fun make_list separator =
let val counter = ref 1; fun make_item item = let val result = Int.toString (!counter) ^ separator ^ item ^ "\n" in counter := !counter + 1; result end in make_item "first" ^ make_item "second" ^ make_item "third" end;
print (make_list ". ")</lang>
Swift
<lang swift>func makeList(_ separator: String) -> String {
var counter = 1 func makeItem(_ item: String) -> String { let result = String(counter) + separator + item + "\n" counter += 1 return result } return makeItem("first") + makeItem("second") + makeItem("third")
}
print(makeList(". "))</lang>
zkl
zkl functions don't have direct access to another functions scope, they are not nested. If a function is defined in another function, the compiler moves it out and hands you a reference to the function. So, you are unable to modify variables in the enclosing scope unless you are given a container which can be modified. Partial application can be used to bind [copies] of scope information to a function, that information is fixed at the point of application and becomes strictly local to the binding function (ie changes do not propagate). A Ref[erence] is a container that holds an object so it can be modified by other entities. <lang zkl>fcn makeList(separator){
counter:=Ref(1); // a container holding a one. A reference. // 'wrap is partial application, in this case binding counter and separator makeItem:='wrap(item){ c:=counter.inc(); String(c,separator,item,"\n") }; makeItem("first") + makeItem("second") + makeItem("third")
}
print(makeList(". "));</lang>
- Output:
1. first 2. second 3. third