Nested function: Difference between revisions
Added Io entry. |
Thundergnat (talk | contribs) →{{header|Perl 6}}: Add Perl 6 |
||
Line 348: | Line 348: | ||
print makeList(". ");</lang> |
print makeList(". ");</lang> |
||
=={{header|Perl 6}}== |
|||
<lang perl6>sub make-List ($separator = ')'){ |
|||
my $count = 1; |
|||
sub make-Item ($item) { "{$count++}$separator $item" } |
|||
join "\n", <first second third>».&make-Item; |
|||
} |
|||
put make-List('.');</lang> |
|||
{{out}} |
|||
<pre>1. first |
|||
2. second |
|||
3. third</pre> |
|||
=={{header|PHP}}== |
=={{header|PHP}}== |
Revision as of 21:55, 28 September 2016
![Task](http://static.miraheze.org/rosettacodewiki/thumb/b/ba/Rcode-button-task-crushed.png/64px-Rcode-button-task-crushed.png)
You are encouraged to solve this task according to the task description, using any language you may know.
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 a list item. 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 cpp>#import <iostream>
- import <string>
- import <sstream>
std::string makeList(std::string separator) {
int counter = 1;
auto makeItem = [=](std::string item) mutable { return (std::ostringstream() << counter++ << separator << item << "\n").str(); };
return makeItem("first") + makeItem("second") + makeItem("third");
}
int main() {
std::cout << makeList(". "); return 0;
}</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>
Common Lisp
<lang lisp>(defun my-make-list (separator)
(let ((counter 0)) (flet ((make-item (item) (format nil "~a~a~a~%" (incf counter) separator item))) (concatenate 'string (make-item "first") (make-item "second") (make-item "third")))))
(format t (my-make-list ". "))</lang>
PS: A function named make-list is already defined in Common Lisp, see specification.
Fortran
Arithmetic statement functions
Fortran allows the user to define functions (and subroutines also) but from first Fortran (1958) on these are compiled as separate items and cannot themselves contain the definition of another function (or subroutine) - except for the special form allowing the definition of what is called an arithmetic statement function, such as follows:<lang Fortran> FUNCTION F(X)
REAL X DIST(U,V,W) = X*SQRT(U**2 + V**2 + W**2) !The contained function. T = EXP(X) F = T + DIST(T,SIN(X),ATAN(X) + 7) !Invoked... END</lang>
This (deranged) function contains within it the definition of function DIST (which must be achieved in a single arithmetic statement), and which has access to all the variables of its containing function as well as its own parameters. The sequence DIST(U,V,W) = etc.
would normally be interpreted as an assignment of a value to an element of an array called DIST, but, no such array has been declared so this must therefore be the definition of an arithmetic statement function. Such functions are defined following any declarations of variables, and precede the normal executable statements such as T = EXP(X)
. Since they are for arithmetic they cannot be used for character manipulations, and the CHARACTER variable only appeared with F77.
Containerisation
With the advent of F90 comes the CONTAINS statement, whereby within a function (or subroutine) but oddly, at its end (but before its END) appears the key word CONTAINS, after which further functions (and subroutines) may be defined in the established manner. These have access to all the variables defined in the containing routine, though if the contained routine declares a name of the containing routine then that outside name becomes inaccessible.
Such contained routines are not themselves allowed to contain routines, so that the nesting is limited to two levels - except that arithmetic statement functions are available, so that three levels could be employed. Languages such as Algol, pl/i, Pascal, etc. impose no such constraint. <lang Fortran> SUBROUTINE POOBAH(TEXT,L,SEP) !I've got a little list!
CHARACTER*(*) TEXT !The supplied scratchpad. INTEGER L !Its length. CHARACTER*(*) SEP !The separator to be used. INTEGER N !A counter. L = 0 !No text is in place. N = 0 !No items added. CALL ADDITEM("first") !Here we go. CALL ADDITEM("second") CALL ADDITEM("third") CONTAINS !Madly, defined after usage. SUBROUTINE ADDITEM(X) !A contained routine. CHARACTER*(*) X !The text of the item. N = N + 1 !Count another item in. TEXT(L + 1:L + 1) = CHAR(ICHAR("0") + N) !Place the single-digit number. L = L + 1 !Rather than mess with unknown-length numbers. LX = LEN(SEP) !Now for the separator. TEXT(L + 1:L + LX) = SEP !Placed. L = L + LX !Advance the finger. LX = LEN(X) !Trailing spaces will be included. TEXT(L + 1:L + LX) = X !Placed. L = L + LX !Advance the finger. L = L + 1 !Finally, TEXT(L:L) = CHAR(10) !Append an ASCII line feed. Starts a new line. END SUBROUTINE ADDITEM !That was bitty. END SUBROUTINE POOBAH !But only had to be written once.
PROGRAM POKE CHARACTER*666 TEXT !Surely sufficient. INTEGER L CALL POOBAH(TEXT,L,". ") WRITE (6,"(A)") TEXT(1:L) END</lang>
Fortran doesn't offer a "list" construction as a built-in facility so it seemed easiest to prepare the list in a CHARACTER variable. These do not have a length attribute as in a string, the LEN function reports the size of the character variable not something such as the current length of a string varying from zero to the storage limit. So, the length of the in-use portion is tracked with the aid of an auxiliary variable, and one must decide on a sufficiently large scratchpad area to hold the anticipated result. And, since the items are of varying length, the length of the whole sequence is returned, not the number of items. Subroutine POOBAH could be instead a function, but, it would have to return a fixed-size result (as in say CHARACTER*66 FUNCTION POOBAH(SEP)
) and can't return a length as well, unless via messing with a global variable such as in COMMON or via an additional parameter as with the L above.
To achieve the required output of one item per line would mean the output of one item at a time, and all the items are packed into TEXT with unknown boundaries. A single character sequence seemed less trouble, but to achieve the one-item-per-line layout meant inserting control codes to start a new line. Oddly, the CHAR(10) is the linefeed character in ASCII but on this windows system it is treated as CRLF whereas CR returned to the start of the line with no advance. If output were to go to an old-style lineprinter, such in-line control codes would not be recognised.
When storage is abundant
Another way of providing a "list" is via an array as in CHARACTER*28 TEXT(9)
) so that each item occupied one element, and the maddening question "how long is a piece of string" arises twice: how much storage to allow for each element when all must be as long as the longest text expected, and, how many elements are to be allowed for.<lang Fortran> SUBROUTINE POOBAH(TEXT,N,SEP) !I've got a little list!
CHARACTER*(*) TEXT(*) !The supplied scratchpad. INTEGER N !Entry count. CHARACTER*(*) SEP !The separator to be used. N = 0 !No items added. CALL ADDITEM("first") !Here we go. CALL ADDITEM("second") CALL ADDITEM("third") CONTAINS !Madly, defined after usage. SUBROUTINE ADDITEM(X) !A contained routine. CHARACTER*(*) X !The text of the item to add. N = N + 1 !Count another item in. WRITE (TEXT(N),1) N,SEP,X !Place the N'th text, suitably decorated.. 1 FORMAT (I1,2A) !Allowing only a single digit. END SUBROUTINE ADDITEM !That was simple. END SUBROUTINE POOBAH !Still worth a subroutine.
PROGRAM POKE CHARACTER*28 TEXT(9) !Surely sufficient. INTEGER N CALL POOBAH(TEXT,N,". ") WRITE (6,"(A)") (TEXT(I)(1:LEN_TRIM(TEXT(I))), I = 1,N) END</lang>
The output statement could be WRITE (6,"(A)") TEXT(1:N)
but this would write out the trailing spaces in each element. A TRIM intrinsic function may be available, but, leading spaces may be desired in the case that there are to be more than nine elements. If so, FORMAT (I2,2A)
would be needed up to ninety-nine, or more generally, I0 format. Except that would not write out leading spaces and would spoil the neatness of a columnar layout. With file names, the lack of leading spaces (or zero digits) leads to the ideas explored in "Natural" sorting. One could define constants via the PARAMETER statement to document the linkage between the number of array elements and the correct FORMAT code, though this is messy because for NMAX elements the format code requires <Log10(NMAX) + 1> digits, and in such an attempt I've seen Log10(10) come out not as one but as 0·9999932 or somesuch, truncating to zero.
The previous method stored the various texts in one CHARACTER variable with no wasted space, but elements could be accessed only sequentially. If element i
were desired, it can only be found after stepping along from the start and if the collection expands beyond a few dozen elements, repeated random access soon becomes slow. If this is important, rather than have the items separated by a special in-line symbol one can instead have an array of fingers to say the end of each item's text. In this case the pooled storage for the texts wastes no space on special symbols but this index array must have some predefined size (and be capable of indexing the size of the pool: 16-bits? 32-bits?), but random access is now easy.
F95 introduced facilities whereby a string-style compound variable with both content and current length could be defined and manipulated, and when assigned to it would be reallocated storage so as to have exactly the size to hold the result. Later fortran standardised such a scheme. Similarly, one could define a data aggregate containing a count N
as well as the TEXT
array and a function could return such a compound entity as its result. It may also be possible to arrange that array TEXT becomes "ragged", that is, TEXT(i) is not always 28 characters long, but only as much as is needed to store the actual item.
Go
<lang go>package main import "fmt"
func makeList(separator string) string {
counter := 1
makeItem := func(item string) string { result := fmt.Sprintf("%d%s%s\n", counter, separator, item) counter += 1 return result }
return makeItem("first") + makeItem("second") + makeItem("third")
}
func main() {
fmt.Print(makeList(". "))
}</lang>
Haskell
<lang haskell>import Control.Monad.ST import Data.STRef
makeList :: String -> String makeList separator = concat $ runST $ do
counter <- newSTRef 1 let makeItem item = do x <- readSTRef counter let result = show x ++ separator ++ item ++ "\n" modifySTRef counter (+ 1) return result mapM makeItem ["first", "second", "third"]
main :: IO ()
main = putStr $ makeList ". "</lang>
Io
<lang Io>makeList := method(seperator,
counter := 1 makeItem := method(item, result := counter .. seperator .. item .. "\n" counter = counter + 1 result ) makeItem("first") .. makeItem("second") .. makeItem("third")
) makeList(". ") print</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>
Java
Since version 8, Java has limited support for nested functions. All variables from the outer function that are accessed by the inner function have to be _effectively final_. This means that the counter cannot be a simple int variable; the closest way to emulate it is the AtomicInteger class.
<lang java>import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Function;
public class NestedFunctionsDemo {
static String makeList(String separator) { AtomicInteger counter = new AtomicInteger(1);
Function<String, String> makeItem = item -> counter.getAndIncrement() + separator + item + "\n";
return makeItem.apply("first") + makeItem.apply("second") + makeItem.apply("third"); }
public static void main(String[] args) { System.out.println(makeList(". ")); }
}</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>
Perl 6
<lang perl6>sub make-List ($separator = ')'){
my $count = 1;
sub make-Item ($item) { "{$count++}$separator $item" }
join "\n", <first second third>».&make-Item;
}
put make-List('.');</lang>
- Output:
1. first 2. second 3. third
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>
PicoLisp
<lang PicoLisp>(de makeList (Sep)
(let (Cnt 0 makeItem '((Str) (prinl (inc 'Cnt) Sep Str))) (makeItem "first") (makeItem "second") (makeItem "third") ) )
(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>
Ruby
<lang ruby>def makeList(separator)
counter = 1
makeItem = lambda {|item| result = "#{counter}#{separator}#{item}\n" counter += 1 result }
makeItem["first"] + makeItem["second"] + makeItem["third"]
end
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