Nested function: Difference between revisions
m Sidef comes before Simula |
Added PL/M |
||
(49 intermediate revisions by 25 users not shown) | |||
Line 1: | Line 1: | ||
{{task}} |
{{task}} |
||
[[Category:Scope]][[Category:Functions and subroutines]] |
|||
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. |
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''' |
|||
;Task: |
|||
Write a program consisting of two nested functions that prints the following text. |
Write a program consisting of two nested functions that prints the following text. |
||
Line 15: | Line 16: | ||
The inner function (called <tt>MakeItem</tt> or equivalent) is responsible for creating a list item. It accesses the separator from the outer function and modifies the counter. |
The inner function (called <tt>MakeItem</tt> or equivalent) is responsible for creating a list item. It accesses the separator from the outer function and modifies the counter. |
||
'''References:''' |
|||
;References: |
|||
:* [[wp:Nested function|Nested function]] |
:* [[wp:Nested function|Nested function]] |
||
<br><br> |
|||
=={{header|11l}}== |
|||
[[Category:Scope]][[Category:Functions and subroutines]] |
|||
{{trans|Python}} |
|||
<syntaxhighlight lang="11l">F makeList(separator) |
|||
V counter = 1 |
|||
F makeItem(item) |
|||
-V result = @counter‘’@separator‘’item"\n" |
|||
@counter++ |
|||
R result |
|||
R makeItem(‘first’)‘’makeItem(‘second’)‘’makeItem(‘third’) |
|||
print(makeList(‘. ’))</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
1. first |
|||
2. second |
|||
3. third |
|||
</pre> |
|||
=={{header|Ada}}== |
=={{header|Ada}}== |
||
< |
<syntaxhighlight lang="ada">with Ada.Text_IO; |
||
procedure Nested_Functions is -- 'Nested_Functions' is the name of 'main' |
procedure Nested_Functions is -- 'Nested_Functions' is the name of 'main' |
||
Line 45: | Line 67: | ||
Ada.Text_IO.Put_Line(Item); |
Ada.Text_IO.Put_Line(Item); |
||
end loop; |
end loop; |
||
end Nested_Functions;</ |
end Nested_Functions;</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>$ ./nested_functions |
<pre>$ ./nested_functions |
||
Line 51: | Line 73: | ||
2. Second |
2. Second |
||
3. Third |
3. Third |
||
</pre> |
|||
=={{header|68000 Assembly}}== |
|||
<syntaxhighlight lang="68000devpac">;program starts here, after loading palettes etc. |
|||
MOVE.W #3,D1 |
|||
MOVE.W #'.',D4 |
|||
JSR MakeList |
|||
jmp * ;halt |
|||
MakeList: |
|||
MOVE.W #1,D0 |
|||
loop_MakeList: |
|||
MOVE.W D0,-(SP) |
|||
JSR PrintHex |
|||
MOVE.B D4,D0 ;load separator into D0 |
|||
JSR PrintChar |
|||
MOVE.B #' ',D0 |
|||
JSR PrintChar |
|||
MOVE.W (SP)+,D0 |
|||
JSR MakeItem |
|||
CMP.W D0,D1 |
|||
BCC loop_MakeList ;back to start |
|||
RTS |
|||
MakeItem: |
|||
MOVE.W D0,D2 |
|||
SUBQ.W #1,D2 |
|||
LSL.W #2,D2 |
|||
LEA PointerToText,A0 |
|||
MOVE.L (A0,D2),A3 |
|||
JSR PrintString |
|||
JSR NewLine |
|||
ADDQ.W #1,D0 |
|||
RTS |
|||
PointerToText: |
|||
DC.L FIRST,SECOND,THIRD |
|||
FIRST: |
|||
DC.B "FIRST",0 |
|||
EVEN |
|||
SECOND: |
|||
DC.B "SECOND",0 |
|||
EVEN |
|||
THIRD: |
|||
DC.B "THIRD",0 |
|||
EVEN</syntaxhighlight> |
|||
{{out}} |
|||
[https://ibb.co/mqCKVGy Output running on MAME] |
|||
Also displayed here: |
|||
<pre> |
|||
01. FIRST |
|||
02. SECOND |
|||
03. THIRD |
|||
</pre> |
</pre> |
||
=={{header|ALGOL 68}}== |
=={{header|ALGOL 68}}== |
||
< |
<syntaxhighlight lang="algol68">PROC make list = ( STRING separator )STRING: |
||
BEGIN |
BEGIN |
||
INT counter := 0; |
INT counter := 0; |
||
Line 66: | Line 149: | ||
print( ( make list( ". " ) ) ) |
print( ( make list( ". " ) ) ) |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|ALGOL W}}== |
=={{header|ALGOL W}}== |
||
Algol W strings are fixed length which makes this slightly more complicated than the Algol 68 solution. |
Algol W strings are fixed length which makes this slightly more complicated than the Algol 68 solution. |
||
< |
<syntaxhighlight lang="algolw">begin |
||
string(30) procedure makeList ( string(2) value separator ) ; |
string(30) procedure makeList ( string(2) value separator ) ; |
||
begin |
begin |
||
Line 94: | Line 177: | ||
end; % makeList % |
end; % makeList % |
||
write( makeList( ". " ) ) |
write( makeList( ". " ) ) |
||
end.</ |
end.</syntaxhighlight> |
||
=={{header|AppleScript}}== |
=={{header|AppleScript}}== |
||
< |
<syntaxhighlight lang="applescript">--------------------- NESTED FUNCTION -------------------- |
||
-- makeList :: String -> String |
-- makeList :: String -> String |
||
Line 115: | Line 198: | ||
end makeList |
end makeList |
||
--------------------------- TEST ------------------------- |
|||
on run |
on run |
||
Line 123: | Line 206: | ||
-------------------- GENERIC FUNCTIONS ------------------- |
|||
-- mReturn :: First-class m => (a -> b) -> m (a -> b) |
|||
on mReturn(f) |
|||
-- 2nd class handler function lifted into 1st class script wrapper. |
|||
if script is class of f then |
|||
f |
|||
else |
|||
script |
|||
property |λ| : f |
|||
end script |
|||
end if |
|||
end mReturn |
|||
-- map :: (a -> b) -> [a] -> [b] |
-- map :: (a -> b) -> [a] -> [b] |
||
on map(f, xs) |
on map(f, xs) |
||
-- The list obtained by applying f |
|||
-- to each element of xs. |
|||
tell mReturn(f) |
tell mReturn(f) |
||
set lng to length of xs |
set lng to length of xs |
||
Line 135: | Line 233: | ||
return lst |
return lst |
||
end tell |
end tell |
||
end map |
end map</syntaxhighlight> |
||
-- Lift 2nd class handler function into 1st class script wrapper |
|||
-- mReturn :: Handler -> Script |
|||
on mReturn(f) |
|||
if class of f is script then |
|||
f |
|||
else |
|||
script |
|||
property |λ| : f |
|||
end script |
|||
end if |
|||
end mReturn</lang> |
|||
{{Out}} |
{{Out}} |
||
<pre>1. first |
<pre>1. first |
||
Line 156: | Line 242: | ||
Note, however, that mutation creates redundant complexity and loss of referential transparency. Functions which modify values outside their own scope are rarely, if ever, necessary, and always best avoided. Simpler and sounder here to derive the incrementing index either by zipping the input list with a range of integers, or by inheriting it from the higher order map function: |
Note, however, that mutation creates redundant complexity and loss of referential transparency. Functions which modify values outside their own scope are rarely, if ever, necessary, and always best avoided. Simpler and sounder here to derive the incrementing index either by zipping the input list with a range of integers, or by inheriting it from the higher order map function: |
||
< |
<syntaxhighlight lang="applescript">-- makeList :: String -> String |
||
on makeList(separator) |
on makeList(separator) |
||
Line 167: | Line 253: | ||
map(makeItem, ["first", "second", "third"]) as string |
map(makeItem, ["first", "second", "third"]) as string |
||
end makeList</ |
end makeList</syntaxhighlight> |
||
=={{header|Arturo}}== |
|||
<syntaxhighlight lang="rebol">makeList: function [separator][ |
|||
counter: 1 |
|||
makeItem: function [item] .export:[counter][ |
|||
result: ~"|counter||separator||item|" |
|||
counter: counter+1 |
|||
return result |
|||
] |
|||
@[ |
|||
makeItem "first" |
|||
makeItem "second" |
|||
makeItem "third" |
|||
] |
|||
] |
|||
print join.with:"\n" makeList ". "</syntaxhighlight> |
|||
{{out}} |
|||
<pre>1. first |
|||
2. second |
|||
3. third</pre> |
|||
=={{header|ATS}}== |
=={{header|ATS}}== |
||
<syntaxhighlight lang="ats"> |
|||
<lang ATS> |
|||
(* ****** ****** *) |
(* ****** ****** *) |
||
// |
// |
||
Line 208: | Line 319: | ||
(* ****** ****** *) |
(* ****** ****** *) |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|BQN}}== |
|||
<syntaxhighlight lang="bqn">MakeList ← { |
|||
nl←@+10 ⋄ s←𝕩 ⋄ i←0 |
|||
MakeItem ← {i+↩1 ⋄ (•Fmt i)∾s∾𝕩} |
|||
(⊣∾nl∾⊢)´MakeItem¨"first"‿"second"‿"third" |
|||
}</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
MakeList ". " |
|||
"1. first |
|||
2. second |
|||
3. third" |
|||
</pre> |
|||
=={{header|C}}== |
=={{header|C}}== |
||
Line 218: | Line 343: | ||
'''IMPORTANT''' This implementation will only work with GCC. Go through the link above for details. |
'''IMPORTANT''' This implementation will only work with GCC. Go through the link above for details. |
||
<syntaxhighlight lang="c"> |
|||
<lang C> |
|||
#include<stdlib.h> |
#include<stdlib.h> |
||
#include<stdio.h> |
#include<stdio.h> |
||
Line 256: | Line 381: | ||
return 0; |
return 0; |
||
} |
} |
||
</syntaxhighlight> |
|||
</lang> |
|||
Output: |
Output: |
||
<pre> |
<pre> |
||
Line 264: | Line 389: | ||
</pre> |
</pre> |
||
=={{header|C |
=={{header|C sharp|C#}}== |
||
<syntaxhighlight lang="csharp">string MakeList(string separator) |
|||
{{works with|C++11}} |
|||
<lang cpp>#include <iostream> |
|||
#include <string> |
|||
#include <vector> |
|||
std::vector<std::string> makeList(std::string separator) { |
|||
auto counter = 0; |
|||
auto makeItem = [&](std::string item) { |
|||
return std::to_string(++counter) + separator + item; |
|||
}; |
|||
return {makeItem("first"), makeItem("second"), makeItem("third")}; |
|||
} |
|||
int main() { |
|||
for (auto item : makeList(". ")) |
|||
std::cout << item << "\n"; |
|||
}</lang> |
|||
=={{header|C#}}== |
|||
<lang csharp>string MakeList(string separator) |
|||
{ |
{ |
||
int counter = 1; |
int counter = 1; |
||
Line 293: | Line 399: | ||
} |
} |
||
Console.WriteLine(MakeList(". "));</ |
Console.WriteLine(MakeList(". "));</syntaxhighlight> |
||
'''Update'''<br/> |
'''Update'''<br/> |
||
As of C#7, we can nest actual methods inside other methods instead of creating delegate instances. They can even be declared after the return statement. |
As of C#7, we can nest actual methods inside other methods instead of creating delegate instances. They can even be declared after the return statement. |
||
< |
<syntaxhighlight lang="csharp">string MakeList2(string separator) |
||
{ |
{ |
||
int counter = 1; |
int counter = 1; |
||
Line 303: | Line 409: | ||
//using string interpolation |
//using string interpolation |
||
string MakeItem(string item) => $"{counter++}{separator}{item}\n"; |
string MakeItem(string item) => $"{counter++}{separator}{item}\n"; |
||
}</ |
}</syntaxhighlight> |
||
=={{header|C++}}== |
|||
{{works with|C++11}} |
|||
<syntaxhighlight lang="cpp">#include <iostream> |
|||
#include <string> |
|||
#include <vector> |
|||
std::vector<std::string> makeList(std::string separator) { |
|||
auto counter = 0; |
|||
auto makeItem = [&](std::string item) { |
|||
return std::to_string(++counter) + separator + item; |
|||
}; |
|||
return {makeItem("first"), makeItem("second"), makeItem("third")}; |
|||
} |
|||
int main() { |
|||
for (auto item : makeList(". ")) |
|||
std::cout << item << "\n"; |
|||
}</syntaxhighlight> |
|||
=={{header|Clojure}}== |
=={{header|Clojure}}== |
||
< |
<syntaxhighlight lang="clojure">(defn make-list [separator] |
||
(let [x (atom 0)] |
(let [x (atom 0)] |
||
(letfn [(make-item [item] (swap! x inc) (println (format "%s%s%s" @x separator item)))] |
(letfn [(make-item [item] (swap! x inc) (println (format "%s%s%s" @x separator item)))] |
||
Line 314: | Line 439: | ||
(make-item "third")))) |
(make-item "third")))) |
||
(make-list ". ")</ |
(make-list ". ")</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 325: | Line 450: | ||
=={{header|Common Lisp}}== |
=={{header|Common Lisp}}== |
||
< |
<syntaxhighlight lang="lisp">(defun my-make-list (separator) |
||
(let ((counter 0)) |
(let ((counter 0)) |
||
(flet ((make-item (item) |
(flet ((make-item (item) |
||
Line 334: | Line 459: | ||
(make-item "third"))))) |
(make-item "third"))))) |
||
(format t (my-make-list ". "))</ |
(format t (my-make-list ". "))</syntaxhighlight> |
||
''PS: A function named make-list is already defined in Common Lisp, see [http://www.lispworks.com/documentation/HyperSpec/Body/f_mk_lis.htm#make-list specification].'' |
''PS: A function named make-list is already defined in Common Lisp, see [http://www.lispworks.com/documentation/HyperSpec/Body/f_mk_lis.htm#make-list specification].'' |
||
=={{header|Cowgol}}== |
|||
<syntaxhighlight lang="cowgol">include "cowgol.coh"; |
|||
include "strings.coh"; |
|||
sub MakeList(sep: [uint8], buf: [uint8]): (out: [uint8]) is |
|||
out := buf; # return begin of buffer for ease of use |
|||
var counter: uint32 := 0; |
|||
# Add item to string |
|||
sub AddStr(str: [uint8]) is |
|||
var length := StrLen(str); |
|||
MemCopy(str, length, buf); |
|||
buf := buf + length; |
|||
end sub; |
|||
sub MakeItem(item: [uint8]) is |
|||
counter := counter + 1; |
|||
buf := UIToA(counter, 10, buf); |
|||
AddStr(sep); |
|||
AddStr(item); |
|||
AddStr("\n"); |
|||
end sub; |
|||
MakeItem("first"); |
|||
MakeItem("second"); |
|||
MakeItem("third"); |
|||
[buf] := 0; # terminate string |
|||
end sub; |
|||
var buffer: uint8[100]; |
|||
print(MakeList(". ", &buffer as [uint8]));</syntaxhighlight> |
|||
{{out}} |
|||
<pre>1. first |
|||
2. second |
|||
3. third</pre> |
|||
=={{header|D}}== |
=={{header|D}}== |
||
< |
<syntaxhighlight lang="d">string makeList(string seperator) { |
||
int counter = 1; |
int counter = 1; |
||
Line 354: | Line 518: | ||
import std.stdio : writeln; |
import std.stdio : writeln; |
||
writeln(makeList(". ")); |
writeln(makeList(". ")); |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
|||
<pre>1. first |
|||
2. second |
|||
3. third</pre> |
|||
=={{header|Delphi}}== |
=={{header|Delphi}}== |
||
''See [[#Pascal|Pascal]]'' |
''See [[#Pascal|Pascal]]'' |
||
=={{header|Ecstasy}}== |
|||
<syntaxhighlight lang="java"> |
|||
module NestedFunction { |
|||
static String makeList(String separator) { |
|||
Int counter = 1; |
|||
function String(String) makeItem = item -> $"{counter++}{separator}{item}\n"; |
|||
return makeItem("first") |
|||
+ makeItem("second") |
|||
+ makeItem("third"); |
|||
} |
|||
void run() { |
|||
@Inject Console console; |
|||
console.print(makeList(". ")); |
|||
} |
|||
} |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
1. first |
|||
2. second |
|||
3. third |
|||
</pre> |
|||
=={{header|Elena}}== |
=={{header|Elena}}== |
||
ELENA |
ELENA 6.x : |
||
< |
<syntaxhighlight lang="elena">import extensions; |
||
MakeList(separator) |
MakeList(separator) |
||
Line 367: | Line 564: | ||
var counter := 1; |
var counter := 1; |
||
var makeItem := (item){ var retVal := counter. |
var makeItem := (item){ var retVal := counter.toPrintable() + separator + item + newLineConstant; counter += 1; ^ retVal }; |
||
^ makeItem("first") + makeItem("second") + makeItem("third") |
^ makeItem("first") + makeItem("second") + makeItem("third") |
||
Line 375: | Line 572: | ||
{ |
{ |
||
console.printLine(MakeList(". ")) |
console.printLine(MakeList(". ")) |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 385: | Line 582: | ||
=={{header|Elixir}}== |
=={{header|Elixir}}== |
||
Elixir data are immutable. Anonymous functions are closures and as such they can access variables that are in scope when the function is defined. Keep in mind a variable assigned inside a function does not affect its surrounding environment: |
Elixir data are immutable. Anonymous functions are closures and as such they can access variables that are in scope when the function is defined. Keep in mind a variable assigned inside a function does not affect its surrounding environment: |
||
< |
<syntaxhighlight lang="elixir">defmodule Nested do |
||
def makeList(separator) do |
def makeList(separator) do |
||
counter = 1 |
counter = 1 |
||
Line 399: | Line 596: | ||
end |
end |
||
IO.write Nested.makeList(". ")</ |
IO.write Nested.makeList(". ")</syntaxhighlight> |
||
{{out}} |
|||
<pre> |
|||
1. first |
|||
2. second |
|||
3. third |
|||
</pre> |
|||
=={{header|EMal}}== |
|||
<syntaxhighlight lang="emal"> |
|||
fun makeList = List by text separator |
|||
int counter = 0 |
|||
fun makeItem = text by text item |
|||
return ++counter + separator + item |
|||
end |
|||
return text[makeItem("first"), makeItem("second"), makeItem("third")] |
|||
end |
|||
for each text item in makeList(". ") do writeLine(item) end |
|||
</syntaxhighlight> |
|||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 413: | Line 628: | ||
If we really wanted, we could also define a named word inside <code>make-list</code> at run time, using words such as <code>define</code> in the <code>words</code> vocabulary. |
If we really wanted, we could also define a named word inside <code>make-list</code> at run time, using words such as <code>define</code> in the <code>words</code> vocabulary. |
||
< |
<syntaxhighlight lang="factor">USING: io kernel math math.parser locals qw sequences ; |
||
IN: rosetta-code.nested-functions |
IN: rosetta-code.nested-functions |
||
Line 425: | Line 640: | ||
; |
; |
||
". " make-list write</ |
". " make-list write</syntaxhighlight> |
||
=={{header|Fōrmulæ}}== |
|||
In [http://wiki.formulae.org/Nested_function this] page you can see the solution of this task. |
|||
Fōrmulæ programs are not textual, visualization/edition of programs is done showing/manipulating structures but not text ([http://wiki.formulae.org/Editing_F%C5%8Drmul%C3%A6_expressions more info]). Moreover, there can be multiple visual representations of the same program. Even though it is possible to have textual representation —i.e. XML, JSON— they are intended for transportation effects more than visualization and edition. |
|||
The option to show Fōrmulæ programs and their results is showing images. Unfortunately images cannot be uploaded in Rosetta Code. |
|||
=={{header|Fortran}}== |
=={{header|Fortran}}== |
||
===Arithmetic statement functions=== |
===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:< |
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:<syntaxhighlight lang="fortran"> FUNCTION F(X) |
||
REAL X |
REAL X |
||
DIST(U,V,W) = X*SQRT(U**2 + V**2 + W**2) !The contained function. |
DIST(U,V,W) = X*SQRT(U**2 + V**2 + W**2) !The contained function. |
||
T = EXP(X) |
T = EXP(X) |
||
F = T + DIST(T,SIN(X),ATAN(X) + 7) !Invoked... |
F = T + DIST(T,SIN(X),ATAN(X) + 7) !Invoked... |
||
END</ |
END</syntaxhighlight> |
||
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 <code>DIST(U,V,W) = ''etc.''</code> 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 <code>T = EXP(X)</code>. Since they are for arithmetic they cannot be used for character manipulations, and the CHARACTER variable only appeared with F77. |
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 <code>DIST(U,V,W) = ''etc.''</code> 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 <code>T = EXP(X)</code>. Since they are for arithmetic they cannot be used for character manipulations, and the CHARACTER variable only appeared with F77. |
||
Line 448: | Line 655: | ||
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 used in the containing routine then that outside name becomes inaccessible. |
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 used in 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. < |
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. <syntaxhighlight lang="fortran"> SUBROUTINE POOBAH(TEXT,L,SEP) !I've got a little list! |
||
CHARACTER*(*) TEXT !The supplied scratchpad. |
CHARACTER*(*) TEXT !The supplied scratchpad. |
||
INTEGER L !Its length. |
INTEGER L !Its length. |
||
Line 480: | Line 687: | ||
CALL POOBAH(TEXT,L,". ") |
CALL POOBAH(TEXT,L,". ") |
||
WRITE (6,"(A)") TEXT(1:L) |
WRITE (6,"(A)") TEXT(1:L) |
||
END</ |
END</syntaxhighlight> |
||
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 <code>CHARACTER*66 FUNCTION POOBAH(SEP)</code>) 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. |
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 <code>CHARACTER*66 FUNCTION POOBAH(SEP)</code>) 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. |
||
Line 489: | Line 696: | ||
===When storage is abundant=== |
===When storage is abundant=== |
||
Another way of providing a "list" is via an array as in <code>CHARACTER*28 TEXT(9)</code>) 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.< |
Another way of providing a "list" is via an array as in <code>CHARACTER*28 TEXT(9)</code>) 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.<syntaxhighlight lang="fortran"> SUBROUTINE POOBAH(TEXT,N,SEP) !I've got a little list! |
||
CHARACTER*(*) TEXT(*) !The supplied scratchpad. |
CHARACTER*(*) TEXT(*) !The supplied scratchpad. |
||
INTEGER N !Entry count. |
INTEGER N !Entry count. |
||
Line 511: | Line 718: | ||
CALL POOBAH(TEXT,N,". ") |
CALL POOBAH(TEXT,N,". ") |
||
WRITE (6,"(A)") (TEXT(I)(1:LEN_TRIM(TEXT(I))), I = 1,N) |
WRITE (6,"(A)") (TEXT(I)(1:LEN_TRIM(TEXT(I))), I = 1,N) |
||
END</ |
END</syntaxhighlight> |
||
The output statement could be <code>WRITE (6,"(A)") TEXT(1:N)</code> 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, <code>FORMAT (I2,2A)</code> 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|"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 output statement could be <code>WRITE (6,"(A)") TEXT(1:N)</code> 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, <code>FORMAT (I2,2A)</code> 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|"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. |
||
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 <code>N</code> as well as the <code>TEXT</code> 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. |
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 <code>N</code> as well as the <code>TEXT</code> 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. |
||
=={{header|FreeBASIC}}== |
|||
FreeBASIC does not currently support either nested procedures or lambda expressions. |
|||
The best we can do here is to create two separate procedures but pass the state of the first procedure |
|||
by reference to the second procedure so it can be modified by the latter. |
|||
<lang freebasic>' FB 1.05.0 Win64 |
|||
Sub makeItem(sep As String, ByRef counter As Integer, text As String) |
|||
counter += 1 |
|||
Print counter; sep; text |
|||
End Sub |
|||
Sub makeList(sep As String) |
|||
Dim a(0 To 2) As String = {"first", "second", "third"} |
|||
Dim counter As Integer = 0 |
|||
While counter < 3 |
|||
makeItem(sep, counter, a(counter)) |
|||
Wend |
|||
End Sub |
|||
makeList ". " |
|||
Print |
|||
Print "Press any key to quit" |
|||
Sleep |
|||
</lang> |
|||
{{out}} |
|||
<pre> |
|||
1. first |
|||
2. second |
|||
3. third |
|||
</pre> |
|||
=={{header|Free Pascal}}== |
=={{header|Free Pascal}}== |
||
< |
<syntaxhighlight lang="pascal">// In Pascal, functions always _have_ to return _some_ value, |
||
// but the the task doesn’t specify what to return. |
// but the the task doesn’t specify what to return. |
||
// Hence makeList and makeItem became procedures. |
// Hence makeList and makeItem became procedures. |
||
Line 588: | Line 761: | ||
makeItem; |
makeItem; |
||
makeItem; |
makeItem; |
||
end;</ |
end;</syntaxhighlight> |
||
=={{header|FreeBASIC}}== |
|||
FreeBASIC does not currently support either nested procedures or lambda expressions. |
|||
The best we can do here is to create two separate procedures but pass the state of the first procedure |
|||
by reference to the second procedure so it can be modified by the latter. |
|||
<syntaxhighlight lang="freebasic">' FB 1.05.0 Win64 |
|||
Sub makeItem(sep As String, ByRef counter As Integer, text As String) |
|||
counter += 1 |
|||
Print counter; sep; text |
|||
End Sub |
|||
Sub makeList(sep As String) |
|||
Dim a(0 To 2) As String = {"first", "second", "third"} |
|||
Dim counter As Integer = 0 |
|||
While counter < 3 |
|||
makeItem(sep, counter, a(counter)) |
|||
Wend |
|||
End Sub |
|||
makeList ". " |
|||
Print |
|||
Print "Press any key to quit" |
|||
Sleep |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
1. first |
|||
2. second |
|||
3. third |
|||
</pre> |
|||
=={{header|Fōrmulæ}}== |
|||
{{FormulaeEntry|page=https://formulae.org/?script=examples/Nested_function}} |
|||
'''Solution''' |
|||
[[File:Fōrmulæ - Nested function 01.png]] |
|||
[[File:Fōrmulæ - Nested function 02.png]] |
|||
[[File:Fōrmulæ - Nested function 03.png]] |
|||
=={{header|Go}}== |
=={{header|Go}}== |
||
< |
<syntaxhighlight lang="go">package main |
||
import "fmt" |
import "fmt" |
||
Line 609: | Line 828: | ||
func main() { |
func main() { |
||
fmt.Print(makeList(". ")) |
fmt.Print(makeList(". ")) |
||
}</ |
}</syntaxhighlight> |
||
=={{header|Haskell}}== |
=={{header|Haskell}}== |
||
< |
<syntaxhighlight lang="haskell">import Control.Monad.ST |
||
import Data.STRef |
import Data.STRef |
||
Line 628: | Line 847: | ||
main :: IO () |
main :: IO () |
||
main = putStr $ makeList ". "</ |
main = putStr $ makeList ". "</syntaxhighlight> |
||
Or, importing a little less heavy machinery: |
|||
<syntaxhighlight lang="haskell">makeList :: String -> String |
|||
makeList separator = |
|||
let makeItem = (<>) . (<> separator) . show |
|||
in unlines $ zipWith makeItem [1 ..] ["First", "Second", "Third"] |
|||
main :: IO () |
|||
main = putStrLn $ makeList ". "</syntaxhighlight> |
|||
or perhaps: |
|||
<syntaxhighlight lang="haskell">makeList :: String -> String |
|||
makeList separator = |
|||
let makeItem = unlines . zipWith ((<>) . (<> separator) . show) [1..] |
|||
in makeItem ["First", "Second", "Third"] |
|||
main :: IO () |
|||
main = putStrLn $ makeList ". "</syntaxhighlight> |
|||
{{Out}} |
|||
<pre>1. First |
|||
2. Second |
|||
3. Third</pre> |
|||
=={{header|Io}}== |
=={{header|Io}}== |
||
< |
<syntaxhighlight lang="io">makeList := method(separator, |
||
counter := 1 |
counter := 1 |
||
makeItem := method(item, |
makeItem := method(item, |
||
Line 640: | Line 882: | ||
makeItem("first") .. makeItem("second") .. makeItem("third") |
makeItem("first") .. makeItem("second") .. makeItem("third") |
||
) |
) |
||
makeList(". ") print</ |
makeList(". ") print</syntaxhighlight> |
||
=={{header|J}}== |
=={{header|J}}== |
||
Line 648: | Line 890: | ||
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: |
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: |
||
< |
<syntaxhighlight lang="j">MakeList=: dyad define |
||
sep_MakeList_=: x |
sep_MakeList_=: x |
||
cnt_MakeList_=: 0 |
cnt_MakeList_=: 0 |
||
Line 657: | Line 899: | ||
cnt_MakeList_=: cnt_MakeList_+1 |
cnt_MakeList_=: cnt_MakeList_+1 |
||
(":cnt_MakeList_),sep_MakeList_,y,LF |
(":cnt_MakeList_),sep_MakeList_,y,LF |
||
)</ |
)</syntaxhighlight> |
||
Example use: |
Example use: |
||
< |
<syntaxhighlight lang="j"> '. ' MakeList 'first';'second';'third' |
||
1. first |
1. first |
||
2. second |
2. second |
||
3. third |
3. third |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Java}}== |
=={{header|Java}}== |
||
Line 672: | Line 914: | ||
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 <tt>int</tt> variable; the closest way to emulate it is the <tt>AtomicInteger</tt> class. |
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 <tt>int</tt> variable; the closest way to emulate it is the <tt>AtomicInteger</tt> class. |
||
< |
<syntaxhighlight lang="java">import java.util.concurrent.atomic.AtomicInteger; |
||
import java.util.function.Function; |
import java.util.function.Function; |
||
Line 688: | Line 930: | ||
System.out.println(makeList(". ")); |
System.out.println(makeList(". ")); |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
=={{header|JavaScript}}== |
=={{header|JavaScript}}== |
||
< |
<syntaxhighlight lang="javascript">function makeList(separator) { |
||
var counter = 1; |
var counter = 1; |
||
Line 702: | Line 944: | ||
} |
} |
||
console.log(makeList(". "));</ |
console.log(makeList(". "));</syntaxhighlight> |
||
=={{header|jq}}== |
=={{header|jq}}== |
||
< |
<syntaxhighlight lang="jq">def makeList(separator): |
||
# input: {text: _, counter: _} |
# input: {text: _, counter: _} |
||
def makeItem(item): |
def makeItem(item): |
||
Line 717: | Line 959: | ||
; |
; |
||
makeList(". ")</ |
makeList(". ")</syntaxhighlight> |
||
With the above in a file, say program.jq, the invocation: |
With the above in a file, say program.jq, the invocation: |
||
Line 730: | Line 972: | ||
=={{header|Jsish}}== |
=={{header|Jsish}}== |
||
From Javascript entry. |
From Javascript entry. |
||
< |
<syntaxhighlight lang="javascript">/* Nested function, in Jsish */ |
||
function makeList(separator) { |
function makeList(separator) { |
||
var counter = 1; |
var counter = 1; |
||
Line 750: | Line 992: | ||
=!EXPECTEND!= |
=!EXPECTEND!= |
||
*/</ |
*/</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 759: | Line 1,001: | ||
{{works with|Julia|0.6}} |
{{works with|Julia|0.6}} |
||
< |
<syntaxhighlight lang="julia">function makelist(sep::String) |
||
cnt = 1 |
cnt = 1 |
||
Line 771: | Line 1,013: | ||
end |
end |
||
print(makelist(". "))</ |
print(makelist(". "))</syntaxhighlight> |
||
=={{header|Kotlin}}== |
=={{header|Kotlin}}== |
||
< |
<syntaxhighlight lang="scala">// version 1.0.6 |
||
fun makeList(sep: String): String { |
fun makeList(sep: String): String { |
||
Line 787: | Line 1,029: | ||
fun main(args: Array<String>) { |
fun main(args: Array<String>) { |
||
print(makeList(". ")) |
print(makeList(". ")) |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 795: | Line 1,037: | ||
3. third |
3. third |
||
</pre> |
</pre> |
||
=={{header|Lambdatalk}}== |
|||
Lambdatalk has neither closures nor states but we can do that, thanks to mutability of arrays behaving as "sandbox" of mutability. |
|||
<syntaxhighlight lang="scheme"> |
|||
{def makeList |
|||
{def makeItem |
|||
{lambda {:s :a :i} |
|||
{div}{A.first {A.set! 0 {+ {A.first :a} 1} :a}}:s :i}} |
|||
{lambda {:s} |
|||
{S.map {{lambda {:s :a :i} {makeItem :s :a :i}} |
|||
:s {A.new 0}} |
|||
first second third |
|||
}}} |
|||
-> makeList |
|||
{makeList .} |
|||
-> |
|||
1. first |
|||
2. second |
|||
3. third |
|||
</syntaxhighlight> |
|||
=={{header|Lua}}== |
=={{header|Lua}}== |
||
< |
<syntaxhighlight lang="lua">function makeList (separator) |
||
local counter = 0 |
local counter = 0 |
||
local function makeItem(item) |
local function makeItem(item) |
||
Line 807: | Line 1,072: | ||
end |
end |
||
print(makeList(". "))</ |
print(makeList(". "))</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>1. first |
<pre>1. first |
||
Line 816: | Line 1,081: | ||
In M2000 functions may have functions, modules, subs, but these are black boxes. We can define globals for temporary use. Subs can use anything from module/function where we call them. First example use Subs inside a module, when call Make_list two local variables, Separator$ and Counter allocated in same space as module's. So when we call Make_item() these variables are visible. At the exit of sub Make_list local variables destroyed. In second example Letter$ pop a string from stack of values (or an error raised if no string found). |
In M2000 functions may have functions, modules, subs, but these are black boxes. We can define globals for temporary use. Subs can use anything from module/function where we call them. First example use Subs inside a module, when call Make_list two local variables, Separator$ and Counter allocated in same space as module's. So when we call Make_item() these variables are visible. At the exit of sub Make_list local variables destroyed. In second example Letter$ pop a string from stack of values (or an error raised if no string found). |
||
<syntaxhighlight lang="m2000 interpreter"> |
|||
<lang M2000 Interpreter> |
|||
Module Checkit { |
Module Checkit { |
||
Make_List(". ") |
Make_List(". ") |
||
Line 858: | Line 1,123: | ||
Make_List1 ". " |
Make_List1 ". " |
||
</lang> |
|||
Module Make_List (Separator$) { |
|||
Def Counter as Integer |
|||
// Need New before Item_Name$, because the scope is the module scope |
|||
// the scope defined from the calling method. |
|||
// by default a function has a new namespace. |
|||
Function Make_Item(New Item_Name$){ |
|||
Counter++ |
|||
Print Str$(Counter,"")+Separator$+Item_Name$ |
|||
} |
|||
// Call Local place the module scope to function |
|||
// function called like a module |
|||
Call Local Make_Item("First") |
|||
Call Local Make_Item("Second") |
|||
Call Local Make_Item("Third") |
|||
Print "Counter=";Counter // 3 |
|||
} |
|||
Make_List ". " |
|||
Module Make_List (Separator$) { |
|||
Def Counter |
|||
// using Module not Function. |
|||
Module Make_Item(New Item_Name$){ |
|||
Counter++ |
|||
Print Str$(Counter,"")+Separator$+Item_Name$ |
|||
} |
|||
Call Local Make_Item,"First" |
|||
Call Local Make_Item,"Second" |
|||
Call Local Make_Item,"Third" |
|||
Print "Counter=";Counter // 3 |
|||
} |
|||
Make_List ". " |
|||
</syntaxhighlight> |
|||
=={{header|Maple}}== |
=={{header|Maple}}== |
||
<syntaxhighlight lang="maple"> |
|||
<lang Maple> |
|||
makelist:=proc() |
makelist:=proc() |
||
local makeitem,i; |
local makeitem,i; |
||
Line 882: | Line 1,183: | ||
end proc; |
end proc; |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Mathematica}}== |
=={{header|Mathematica}}/{{header|Wolfram Language}}== |
||
< |
<syntaxhighlight lang="mathematica">makeList[sep_String]:=Block[ |
||
{counter=0, makeItem}, |
{counter=0, makeItem}, |
||
makeItem[item_String]:=ToString[++counter]<>sep<>item; |
makeItem[item_String]:=ToString[++counter]<>sep<>item; |
||
makeItem /@ {"first", "second", "third"} |
makeItem /@ {"first", "second", "third"} |
||
] |
] |
||
Scan[Print, makeList[". "]]</ |
Scan[Print, makeList[". "]]</syntaxhighlight> |
||
=={{header|min}}== |
=={{header|min}}== |
||
{{works with|min|0.19.3}} |
{{works with|min|0.19.3}} |
||
Note the <code>@</code> sigil is the key to altering <code>counter</code> in the outer scope. |
Note the <code>@</code> sigil is the key to altering <code>counter</code> in the outer scope. |
||
< |
<syntaxhighlight lang="min">( |
||
:separator |
:separator |
||
1 :counter |
1 :counter |
||
Line 906: | Line 1,207: | ||
) :make-list |
) :make-list |
||
". " make-list print</ |
". " make-list print</syntaxhighlight> |
||
=={{header|MiniScript}}== |
=={{header|MiniScript}}== |
||
Subfunctions can directly read variables in the enclosing scope, but to assign to those variables, they must explicitly use the ''outer'' specifier (added in MiniScript version 1.5). This is similar to how global variables are accessed via ''globals''. |
Subfunctions can directly read variables in the enclosing scope, but to assign to those variables, they must explicitly use the ''outer'' specifier (added in MiniScript version 1.5). This is similar to how global variables are accessed via ''globals''. |
||
< |
<syntaxhighlight lang="miniscript">makeList = function(sep) |
||
counter = 0 |
counter = 0 |
||
makeItem = function(item) |
makeItem = function(item) |
||
Line 919: | Line 1,220: | ||
end function |
end function |
||
print makeList(". ")</ |
print makeList(". ")</syntaxhighlight> |
||
Output: |
Output: |
||
<pre>["1. first", "2. second", "3. third"]</pre> |
<pre>["1. first", "2. second", "3. third"]</pre> |
||
Line 925: | Line 1,226: | ||
=={{header|Nanoquery}}== |
=={{header|Nanoquery}}== |
||
{{trans|Python}} |
{{trans|Python}} |
||
< |
<syntaxhighlight lang="nanoquery">def makeList(separator) |
||
counter = 1 |
counter = 1 |
||
Line 937: | Line 1,238: | ||
end |
end |
||
println makeList(". ")</ |
println makeList(". ")</syntaxhighlight> |
||
=={{header|Nim}}== |
=={{header|Nim}}== |
||
< |
<syntaxhighlight lang="nim">proc makeList(separator: string): string = |
||
var counter = 1 |
var counter = 1 |
||
Line 946: | Line 1,247: | ||
result = $counter & separator & item & "\n" |
result = $counter & separator & item & "\n" |
||
inc counter |
inc counter |
||
return |
|||
makeItem("first") & makeItem("second") & makeItem("third") |
makeItem("first") & makeItem("second") & makeItem("third") |
||
echo $makeList(". ")</ |
echo $makeList(". ")</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 960: | Line 1,260: | ||
=={{header|Objective-C}}== |
=={{header|Objective-C}}== |
||
< |
<syntaxhighlight lang="objc">NSString *makeList(NSString *separator) { |
||
__block int counter = 1; |
__block int counter = 1; |
||
Line 973: | Line 1,273: | ||
NSLog(@"%@", makeList(@". ")); |
NSLog(@"%@", makeList(@". ")); |
||
return 0; |
return 0; |
||
}</ |
}</syntaxhighlight> |
||
=={{header|OCaml}}== |
=={{header|OCaml}}== |
||
< |
<syntaxhighlight lang="ocaml">let make_list separator = |
||
let counter = ref 1 in |
let counter = ref 1 in |
||
Line 989: | Line 1,289: | ||
let () = |
let () = |
||
print_string (make_list ". ")</ |
print_string (make_list ". ")</syntaxhighlight> |
||
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 1,000: | Line 1,300: | ||
=={{header|Pascal}}== |
=={{header|Pascal}}== |
||
''See [[#Free Pascal|Free Pascal]]'' |
''See [[#Free Pascal|Free Pascal]]'' |
||
=={{header|PascalABC.NET}}== |
|||
<syntaxhighlight lang="delphi"> |
|||
procedure MakeList(separator: string); |
|||
var counter := 1; |
|||
procedure MakeItem; |
|||
begin |
|||
Write(counter, separator); |
|||
case counter of |
|||
1: Writeln('first'); |
|||
2: Writeln('second'); |
|||
3: Writeln('third'); |
|||
end; |
|||
counter += 1; |
|||
end; |
|||
begin |
|||
MakeItem; |
|||
MakeItem; |
|||
MakeItem; |
|||
end; |
|||
begin |
|||
MakeList('. '); |
|||
end. |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
1. first |
|||
2. second |
|||
3. third |
|||
</pre> |
|||
=={{header|Perl}}== |
=={{header|Perl}}== |
||
< |
<syntaxhighlight lang="perl">sub makeList { |
||
my $separator = shift; |
my $separator = shift; |
||
my $counter = 1; |
my $counter = 1; |
||
Line 1,012: | Line 1,343: | ||
} |
} |
||
print makeList(". ");</ |
print makeList(". ");</syntaxhighlight> |
||
=={{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|Phix}}== |
=={{header|Phix}}== |
||
There is only partial support for nested functions in Phix. Some prior work (over a single afternoon) has been left |
|||
{{improve|Phix|The Phix compiler needs enhancing to fully support nested functions.}} |
|||
unfinished, anyone interested can see it at [[Nested_function/Phix]], but it was just enough to open the door for |
|||
the two following reasonably acceptable work-arounds.<br> |
|||
Prior to this task, Phix had no support whatsoever for nested functions.<br> |
|||
Note that in both the following you cannot reference any local variables or parameters of the containing function, |
|||
Instead I have taken the first baby steps and documented them.<br> |
|||
but must pass in everything you need explicitly, and anything you need to update must be a reference type, which |
|||
If your distribution does not include the following demo, you need a later version (not yet uploaded at the |
|||
is only dictionaries and class instances, not integers, atoms, sequences, strings, or any user-defined types, as |
|||
time of writing). The source of that demo contains far more detailed information, and any updates.<br> |
|||
they are all effectively read-only. Referring to identifiers in the containing/outer function issues proper errors |
|||
in 1.0.0 and later, prior to that it simply won't work as hoped for. |
|||
Yes, this is pig-ugly, and incomplete. But it is a good start for anyone that needs nested functions, and |
|||
=== using a dictionary === |
|||
shows what can be done in just a few (less than six) hours. |
|||
<syntaxhighlight lang="phix">function MakeList(string sep=". ") |
|||
function MakeItem(integer env, string sep) |
|||
NB as it stands, the compiler front-end "thinks" that l_counter and sep live in the same place. They are |
|||
integer counter = getd("counter",env)+1 |
|||
properly separate in the runtime/VM, but the front-end will happily emit nonsense code if you let it. |
|||
setd("counter",counter,env) |
|||
<lang Phix>-- |
|||
return sprintf("%d%s%s",{counter,sep,{"first","second","third"}[counter]}) |
|||
-- demo\rosetta\Nested_function.exw |
|||
-- ================================ |
|||
-- |
|||
#ilASM{ jmp :fin |
|||
-- |
|||
-- This is, of course, something the compiler should end up doing automatically, |
|||
-- and this assembly, or something similar, should be hidden away in builtins/VM. |
|||
-- |
|||
:%opGetnlv -- [edi] := [esi] from frame edx |
|||
-- nb no reference counting (would be rqd) |
|||
[32] |
|||
sub esi,ebp -- --> frame offset |
|||
@@: |
|||
mov ecx,[ebp+20] -- ebp_prev |
|||
cmp [ecx+8],edx -- rtn |
|||
jne @b |
|||
mov eax,[esi+ecx] |
|||
mov [edi],eax |
|||
[64] |
|||
sub rsi,rbp -- --> frame offset |
|||
@@: |
|||
mov rcx,[rbp+40] -- rbp_prev |
|||
cmp [rcx+16],rdx -- rtn |
|||
jne @b |
|||
mov rax,[rsi+rcx] |
|||
mov [rdi],rax |
|||
[] |
|||
ret |
|||
:%opSetnlv -- [edi] in frame edx := [esi] (zeroed) |
|||
[32] |
|||
sub edi,ebp -- --> frame offset |
|||
@@: |
|||
mov ecx,[ebp+20] -- ebp_prev |
|||
cmp [ecx+8],edx -- rtn |
|||
jne @b |
|||
mov eax,[esi] |
|||
mov [edi+ecx],eax |
|||
-- mov [esi],ebx -- zero src |
|||
[64] |
|||
sub rdi,rbp -- --> frame offset |
|||
@@: |
|||
mov rcx,[rbp+40] -- rbp_prev |
|||
cmp [rcx+16],rdx -- rtn |
|||
jne @b |
|||
mov eax,[rsi] |
|||
mov [rdi+rcx],rax |
|||
-- mov [rsi],rbx -- zero src |
|||
[] |
|||
ret |
|||
::fin |
|||
} |
|||
function MakeList(string sep=". ") |
|||
integer counter = 0 |
|||
function MakeItem() |
|||
-- -- what we'd really like to see: |
|||
-- counter += 1 |
|||
-- return sprintf("%d%s%s",{counter,sep,{"first","second","third"}[counter]}) |
|||
-- bar these locals, some idea of what the compiler should be doing: |
|||
integer l_counter |
|||
string l_sep |
|||
#ilASM{ |
|||
[32] |
|||
mov edx,routine_id(MakeList) |
|||
lea esi,[counter] |
|||
lea edi,[l_counter] |
|||
call :%opGetnlv |
|||
lea esi,[sep] |
|||
lea edi,[l_sep] |
|||
call :%opGetnlv |
|||
[64] |
|||
mov rdx,routine_id(MakeList) |
|||
lea rsi,[counter] |
|||
lea rdi,[l_counter] |
|||
call :%opGetnlv |
|||
lea rsi,[sep] |
|||
lea rdi,[l_sep] |
|||
call :%opGetnlv |
|||
[] |
|||
} |
|||
l_counter += 1 |
|||
#ilASM{ |
|||
[32] |
|||
mov edx,routine_id(MakeList) |
|||
lea esi,[l_counter] |
|||
lea edi,[counter] |
|||
call :%opSetnlv |
|||
[64] |
|||
mov rdx,routine_id(MakeList) |
|||
lea rsi,[l_counter] |
|||
lea rdi,[counter] |
|||
call :%opSetnlv |
|||
[] |
|||
} |
|||
string res = sprintf("%d%s%s",{l_counter,l_sep,{"first","second","third"}[l_counter]}) |
|||
#ilASM{ |
|||
[32] |
|||
mov [l_sep],ebx -- (in lieu of proper refcounting) |
|||
[64] |
|||
mov [l_sep],rbx -- (in lieu of proper refcounting) |
|||
[] |
|||
} |
|||
return res |
|||
end function |
end function |
||
integer counter = new_dict({{"counter",0}}) |
|||
sequence res = {} |
sequence res = {} |
||
for i=1 to 3 do |
for i=1 to 3 do |
||
res = append(res,MakeItem()) |
res = append(res,MakeItem(counter,sep)) |
||
end for |
end for |
||
return res |
return res |
||
end function |
end function |
||
?MakeList()</ |
?MakeList()</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
{"1. first","2. second","3. third"} |
{"1. first","2. second","3. third"} |
||
</pre> |
</pre> |
||
=== using a class === |
|||
{{libheader|Phix/Class}} |
|||
Same output. I trust it is obvious that if you passed in c.count, you would not be able to update it. |
|||
Again note how MakeList's sep ''must'' be explicitly re-passed to MakeItem.<br> |
|||
Also note that the counter class ''cannot'' be made private to MakeList, however as a non-global it would automatically be private to a single source code file. |
|||
<syntaxhighlight lang="phix">class counter |
|||
public integer count |
|||
end class |
|||
function MakeList(string sep=". ") |
|||
function MakeItem(counter c, string sep) |
|||
c.count += 1 |
|||
return sprintf("%d%s%s",{c.count,sep,{"first","second","third"}[c.count]}) |
|||
end function |
|||
counter c = new() |
|||
sequence res = {} |
|||
for i=1 to 3 do |
|||
res = append(res,MakeItem(c,sep)) |
|||
end for |
|||
return res |
|||
end function |
|||
?MakeList()</syntaxhighlight> |
|||
=={{header|PHP}}== |
=={{header|PHP}}== |
||
{{works with|PHP|5.3+}} |
{{works with|PHP|5.3+}} |
||
< |
<syntaxhighlight lang="php"><? |
||
function makeList($separator) { |
function makeList($separator) { |
||
$counter = 1; |
$counter = 1; |
||
Line 1,176: | Line 1,411: | ||
echo makeList(". "); |
echo makeList(". "); |
||
?></ |
?></syntaxhighlight> |
||
=={{header|PicoLisp}}== |
=={{header|PicoLisp}}== |
||
< |
<syntaxhighlight lang="picolisp">(de makeList (Sep) |
||
(let (Cnt 0 makeItem '((Str) (prinl (inc 'Cnt) Sep Str))) |
(let (Cnt 0 makeItem '((Str) (prinl (inc 'Cnt) Sep Str))) |
||
(makeItem "first") |
(makeItem "first") |
||
Line 1,185: | Line 1,420: | ||
(makeItem "third") ) ) |
(makeItem "third") ) ) |
||
(makeList ". ")</ |
(makeList ". ")</syntaxhighlight> |
||
=={{header|PL/M}}== |
|||
{{works with|8080 PL/M Compiler|... under CP/M (or an emulator)}} |
|||
In CP/M and by convention in PL/M, strings are terminated by $.<br/> |
|||
Note the original 8080 PL/M compiler treats lower case letters as spaces in the source, so the list is in upper case in this sample. |
|||
<syntaxhighlight lang="plm"> |
|||
100H: /* USE A NESTED PROCEDURE TO CONSTRUCT A STRING, UPDATING VARIABLES IN */ |
|||
/* THE CONTAINING PROCEDURE */ |
|||
/* CP/M BDOS SYSTEM CALL */ |
|||
BDOS: PROCEDURE( FN, ARG ); DECLARE FN BYTE, ARG ADDRESS; GOTO 5;END; |
|||
/* CONSOLE OUTPUT ROUTINES */ |
|||
PR$STRING: PROCEDURE( S ); DECLARE S ADDRESS; CALL BDOS( 9, S ); END; |
|||
/* CONCATENATES ITEM TO THE END OF STR. STR MUST BE LONG ENOUGH TO HOLD */ |
|||
/* THE CONCATENATED VALUE */ |
|||
CONCAT: PROCEDURE( STR, ITEM ); |
|||
DECLARE ( STR, ITEM ) ADDRESS; |
|||
DECLARE STR$S BASED STR ( 0 )BYTE; |
|||
DECLARE ITEM$S BASED ITEM ( 0 )BYTE; |
|||
DECLARE ( STR$POS, ITEM$POS ) BYTE; |
|||
/* FIND THE CURRENT END OF STR */ |
|||
STR$POS = 0; |
|||
DO WHILE STR$S( STR$POS ) <> '$'; |
|||
STR$POS = STR$POS + 1; |
|||
END; |
|||
/* COPY ITEM TO THE END OF STR */ |
|||
ITEM$POS = 0; |
|||
DO WHILE ITEM$S( ITEM$POS ) <> '$'; |
|||
STR$S( STR$POS ) = ITEM$S( ITEM$POS ); |
|||
ITEM$POS = ITEM$POS + 1; |
|||
STR$POS = STR$POS + 1; |
|||
END; |
|||
STR$S( STR$POS ) = '$'; |
|||
END CONCAT ; |
|||
/* TASK */ |
|||
/* RETURNS THE ADDRESS OF A STRING CONCATENATED FROM CALLS TO THE NESTED */ |
|||
/* MAKE$ITEM PROCEDURE - THE RESULTANT STRING MUST NOT BE MORE */ |
|||
/* THAN 64 CHARACTERS IN LENGTH */ |
|||
MAKE$LIST: PROCEDURE( SEPARATOR )ADDRESS; |
|||
DECLARE SEPARATOR ADDRESS; |
|||
DECLARE LIST$VALUE ( 65 )BYTE; |
|||
DECLARE COUNTER BYTE; |
|||
/* RETURNS THE ADDRESS OF A LIST ITEM, THE LENGTH OF THE ITEM MUST'NT */ |
|||
/* BE MORE THAN 32 CHARACTERS */ |
|||
MAKE$ITEM: PROCEDURE( ITEM )ADDRESS; |
|||
DECLARE ITEM ADDRESS; |
|||
DECLARE LIST$ITEM ( 33 )BYTE; |
|||
COUNTER = COUNTER + 1; |
|||
LIST$ITEM( 0 ) = '0' + COUNTER; |
|||
LIST$ITEM( 1 ) = '$'; |
|||
CALL CONCAT( .LIST$ITEM, SEPARATOR ); |
|||
CALL CONCAT( .LIST$ITEM, ITEM ); |
|||
CALL CONCAT( .LIST$ITEM, .( 0DH, 0AH, '$' ) ); |
|||
RETURN .LIST$ITEM; |
|||
END MAKE$ITEM ; |
|||
COUNTER = 0; |
|||
LIST$VALUE( 0 ) = '$'; |
|||
CALL CONCAT( .LISTVALUE, MAKE$ITEM( .'FIRST$' ) ); |
|||
CALL CONCAT( .LISTVALUE, MAKE$ITEM( .'SECOND$' ) ); |
|||
CALL CONCAT( .LISTVALUE, MAKE$ITEM( .'THIRD$' ) ); |
|||
RETURN .LIST$VALUE; |
|||
END MAKE$LIST ; |
|||
CALL PR$STRING( MAKE$LIST( .'. $' ) ); |
|||
EOF |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
1. FIRST |
|||
2. SECOND |
|||
3. THIRD |
|||
</pre> |
|||
=={{header|Python}}== |
=={{header|Python}}== |
||
{{works with|Python|3+}} |
{{works with|Python|3+}} |
||
< |
<syntaxhighlight lang="python">def makeList(separator): |
||
counter = 1 |
counter = 1 |
||
Line 1,200: | Line 1,522: | ||
return makeItem("first") + makeItem("second") + makeItem("third") |
return makeItem("first") + makeItem("second") + makeItem("third") |
||
print(makeList(". "))</ |
print(makeList(". "))</syntaxhighlight> |
||
=={{header|R}}== |
|||
This also shows that cat's sep argument is not the same as MakeList's. |
|||
<syntaxhighlight lang="rsplus">MakeList <- function(sep) |
|||
{ |
|||
counter <- 0 |
|||
MakeItem <- function() paste0(counter <<- counter + 1, sep, c("first", "second", "third")[counter]) |
|||
cat(replicate(3, MakeItem()), sep = "\n") |
|||
} |
|||
MakeList(". ")</syntaxhighlight> |
|||
{{out}} |
|||
<pre>1. first |
|||
2. second |
|||
3. third</pre> |
|||
=={{header|Racket}}== |
=={{header|Racket}}== |
||
See also [[#Scheme]]; this demonstrates <code>map</code> a higher order function and <code>begin0</code> a form which saves us having to explicitly remember the result. |
See also [[#Scheme]]; this demonstrates <code>map</code> a higher order function and <code>begin0</code> a form which saves us having to explicitly remember the result. |
||
< |
<syntaxhighlight lang="racket">#lang racket |
||
(define (make-list separator) |
(define (make-list separator) |
||
Line 1,217: | Line 1,552: | ||
(apply string-append (map make-item '(first second third)))) |
(apply string-append (map make-item '(first second third)))) |
||
(display (make-list ". "))</ |
(display (make-list ". "))</syntaxhighlight> |
||
{{out}} |
|||
<pre>1. first |
|||
2. second |
|||
3. third</pre> |
|||
=={{header|Raku}}== |
|||
(formerly Perl 6) |
|||
<syntaxhighlight lang="raku" line>sub make-List ($separator = ') '){ |
|||
my $count = 1; |
|||
sub make-Item ($item) { "{$count++}$separator$item" } |
|||
join "\n", <first second third>».&make-Item; |
|||
} |
|||
put make-List('. ');</syntaxhighlight> |
|||
{{out}} |
{{out}} |
||
<pre>1. first |
<pre>1. first |
||
Line 1,227: | Line 1,579: | ||
This REXX version is modeled after the '''FreeBASIC''' example (and it has the |
This REXX version is modeled after the '''FreeBASIC''' example (and it has the |
||
same limitations). |
same limitations). |
||
< |
<syntaxhighlight lang="rexx">/*REXX program demonstrates that functions can be nested (an outer and inner function).*/ |
||
ctr= |
ctr= 0 /*initialize the CTR REXX variable.*/ |
||
call |
call MakeList '. ' /*invoke MakeList with the separator.*/ |
||
exit |
exit 0 /*stick a fork in it, we're all done. */ |
||
/*──────────────────────────────────────────────────────────────────────────────────────*/ |
/*──────────────────────────────────────────────────────────────────────────────────────*/ |
||
MakeItem: parse arg sep,text; ctr= ctr + 1 /*bump the counter variable. */ |
|||
say ctr || sep || word( |
say ctr || sep || word($, ctr) /*display three thingys ───► terminal. */ |
||
return |
return |
||
/*──────────────────────────────────────────────────────────────────────────────────────*/ |
/*──────────────────────────────────────────────────────────────────────────────────────*/ |
||
MakeList: parse arg sep; $= 'first second third' /*obtain an argument; define a string.*/ |
|||
do while ctr<3 |
do while ctr<3 /*keep truckin' until finished. */ |
||
call |
call MakeItem sep, $ /*invoke the MakeItem function. */ |
||
end /*while*/ |
end /*while*/ |
||
return</ |
return</syntaxhighlight> |
||
{{out|output|text= when using the default input:}} |
|||
'''output''' |
|||
<pre> |
<pre> |
||
1. first |
1. first |
||
Line 1,249: | Line 1,601: | ||
=={{header|Ring}}== |
=={{header|Ring}}== |
||
< |
<syntaxhighlight lang="ring"> |
||
# Project : Nested function |
# Project : Nested function |
||
Line 1,263: | Line 1,615: | ||
makeitem(sep, counter, a[counter]) |
makeitem(sep, counter, a[counter]) |
||
end |
end |
||
</syntaxhighlight> |
|||
</lang> |
|||
Output: |
Output: |
||
<pre> |
<pre> |
||
Line 1,270: | Line 1,622: | ||
3. third |
3. third |
||
</pre> |
</pre> |
||
=={{header|RPL}}== |
|||
===Fully compliant=== |
|||
The outer function creates the inner function, then deletes it at its last execution step. |
|||
The <code>\n</code> substring must be replaced by a <code>Newline</code> character when typing the code. |
|||
≪ |
|||
≪ + OVER →STR SWAP + ROT SWAP + SWAP 1 + ≫ ''''MakeItem'''' STO |
|||
"" 1 |
|||
3 PICK "first\n" '''MakeItem''' 3 PICK "second\n" '''MakeItem''' 3 PICK "third\n" '''MakeItem''' |
|||
DROP SWAP DROP |
|||
''''MakeItem'''' PURGE |
|||
≫ |
|||
‘'''MakeList'''’ STO |
|||
". " '''MakeList''' |
|||
{{out}} |
|||
<pre> |
|||
1: "1. first |
|||
2. second |
|||
3. third" |
|||
</pre> |
|||
===Unnamed nested functions=== |
|||
It is more idiomatic in RPL to use unnamed nested functions, which allows the use of local variables and then increases code readability. |
|||
≪ "" 1 |
|||
1 3 '''FOR''' j |
|||
3 PICK { "first\n" "second\n" "third\n" } j GET |
|||
→ sep item ≪ DUP →STR sep + item + ROT SWAP + SWAP 1 + ≫ |
|||
'''NEXT''' |
|||
DROP SWAP DROP |
|||
≫ |
|||
=={{header|Ruby}}== |
=={{header|Ruby}}== |
||
< |
<syntaxhighlight lang="ruby">def makeList(separator) |
||
counter = 1 |
counter = 1 |
||
Line 1,285: | Line 1,667: | ||
end |
end |
||
print makeList(". ")</ |
print makeList(". ")</syntaxhighlight> |
||
=={{header|Rust}}== |
=={{header|Rust}}== |
||
< |
<syntaxhighlight lang="rust">fn make_list(sep: &str) -> String { |
||
let mut counter = 0; |
let mut counter = 0; |
||
let mut make_item = |label| { |
let mut make_item = |label| { |
||
Line 1,304: | Line 1,686: | ||
fn main() { |
fn main() { |
||
println!("{}", make_list(". ")) |
println!("{}", make_list(". ")) |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 1,314: | Line 1,696: | ||
=={{header|Scala}}== |
=={{header|Scala}}== |
||
<syntaxhighlight lang="scala"> |
|||
<lang Scala> |
|||
def main(args: Array[String]) { |
def main(args: Array[String]) { |
||
val sep: String=". " |
val sep: String=". " |
||
Line 1,326: | Line 1,708: | ||
go("third") |
go("third") |
||
} |
} |
||
</ |
</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 1,337: | Line 1,719: | ||
=={{header|Scheme}}== |
=={{header|Scheme}}== |
||
< |
<syntaxhighlight lang="scheme">(define (make-list separator) |
||
(define counter 1) |
(define counter 1) |
||
Line 1,347: | Line 1,729: | ||
(string-append (make-item "first") (make-item "second") (make-item "third"))) |
(string-append (make-item "first") (make-item "second") (make-item "third"))) |
||
(display (make-list ". "))</ |
(display (make-list ". "))</syntaxhighlight> |
||
=={{header|Seed7}}== |
=={{header|Seed7}}== |
||
< |
<syntaxhighlight lang="seed7">$ include "seed7_05.s7i"; |
||
const func string: makeList (in string: separator) is func |
const func string: makeList (in string: separator) is func |
||
Line 1,373: | Line 1,755: | ||
begin |
begin |
||
write(makeList(". ")); |
write(makeList(". ")); |
||
end func;</ |
end func;</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 1,383: | Line 1,765: | ||
=={{header|Sidef}}== |
=={{header|Sidef}}== |
||
< |
<syntaxhighlight lang="ruby">func make_list(separator = ') ') { |
||
var count = 1 |
var count = 1 |
||
Line 1,393: | Line 1,775: | ||
} |
} |
||
say make_list('. ')</ |
say make_list('. ')</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 1,402: | Line 1,784: | ||
=={{header|Simula}}== |
=={{header|Simula}}== |
||
< |
<syntaxhighlight lang="simula">COMMENT CLASS SIMSET IS SIMULA'S STANDARD LINKED LIST DATA TYPE |
||
CLASS HEAD IS THE LIST ITSELF |
CLASS HEAD IS THE LIST ITSELF |
||
CLASS LINK IS THE ELEMENT OF A LIST |
CLASS LINK IS THE ELEMENT OF A LIST |
||
Line 1,459: | Line 1,841: | ||
END. |
END. |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 1,469: | Line 1,851: | ||
=={{header|Standard ML}}== |
=={{header|Standard ML}}== |
||
< |
<syntaxhighlight lang="sml">fun make_list separator = |
||
let |
let |
||
val counter = ref 1; |
val counter = ref 1; |
||
Line 1,483: | Line 1,865: | ||
end; |
end; |
||
print (make_list ". ")</ |
print (make_list ". ")</syntaxhighlight> |
||
=={{header|SuperCollider}}== |
=={{header|SuperCollider}}== |
||
<syntaxhighlight lang="supercollider">( |
|||
<lang SuperCollider>( |
|||
f = { |separator| |
f = { |separator| |
||
var count = 0; |
var count = 0; |
||
Line 1,498: | Line 1,880: | ||
f.(".") |
f.(".") |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Swift}}== |
=={{header|Swift}}== |
||
< |
<syntaxhighlight lang="swift">func makeList(_ separator: String) -> String { |
||
var counter = 1 |
var counter = 1 |
||
Line 1,514: | Line 1,896: | ||
} |
} |
||
print(makeList(". "))</ |
print(makeList(". "))</syntaxhighlight> |
||
=={{header|Tcl}}== |
=={{header|Tcl}}== |
||
The code below satisfies the specification (inspired by the Swift example). The inner function MakeItem (which gains read/write access to its caller's variables via upvar) is defined, called, and then discarded by renaming to {}. suchenwi |
The code below satisfies the specification (inspired by the Swift example). The inner function MakeItem (which gains read/write access to its caller's variables via upvar) is defined, called, and then discarded by renaming to {}. suchenwi |
||
< |
<syntaxhighlight lang="tcl">#!/usr/bin/env tclsh |
||
proc MakeList separator { |
proc MakeList separator { |
||
Line 1,533: | Line 1,915: | ||
} |
} |
||
puts [MakeList ". "] |
puts [MakeList ". "] |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|VBA}}== |
|||
<syntaxhighlight lang="vb">Option Explicit |
|||
Private Const Sep As String = ". " |
|||
Private Counter As Integer |
|||
Sub Main() |
|||
Dim L As Variant |
|||
Counter = 0 |
|||
L = MakeList(Array("first", "second", "third")) |
|||
Debug.Print L |
|||
End Sub |
|||
Function MakeList(Datas) As Variant |
|||
Dim i As Integer |
|||
For i = LBound(Datas) To UBound(Datas) |
|||
MakeList = MakeList & MakeItem(Datas(i)) |
|||
Next i |
|||
End Function |
|||
Function MakeItem(Item As Variant) As Variant |
|||
Counter = Counter + 1 |
|||
MakeItem = Counter & Sep & Item & vbCrLf |
|||
End Function</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
1. first |
|||
2. second |
|||
3. third |
|||
</pre> |
|||
=={{header|Wren}}== |
|||
<syntaxhighlight lang="wren">var makeList = Fn.new { |sep| |
|||
var counter = 0 |
|||
var makeItem = Fn.new { |name| |
|||
counter = counter + 1 |
|||
return "%(counter)%(sep)%(name)" |
|||
} |
|||
var items = [] |
|||
for (name in ["first", "second", "third"]) { |
|||
items.add(makeItem.call(name)) |
|||
} |
|||
System.print(items.join("\n")) |
|||
} |
|||
makeList.call(". ")</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
1. first |
|||
2. second |
|||
3. third |
|||
</pre> |
|||
=={{header|XPL0}}== |
|||
<syntaxhighlight lang="xpl0">proc MakeList(Separator); |
|||
char Separator; |
|||
int Counter; |
|||
proc MakeItem; |
|||
int Ordinals; |
|||
[IntOut(0, Counter); |
|||
Text(0, Separator); |
|||
Ordinals:= [0, "first", "second", "third"]; |
|||
Text(0, Ordinals(Counter)); |
|||
CrLf(0); |
|||
]; |
|||
for Counter:= 1 to 3 do MakeItem; \MakeList procedure |
|||
MakeList(". ") \main procedure</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
1. first |
|||
2. second |
|||
3. third |
|||
</pre> |
|||
=={{header|zkl}}== |
=={{header|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. |
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. |
||
< |
<syntaxhighlight lang="zkl">fcn makeList(separator){ |
||
counter:=Ref(1); // a container holding a one. A reference. |
counter:=Ref(1); // a container holding a one. A reference. |
||
// 'wrap is partial application, in this case binding counter and separator |
// 'wrap is partial application, in this case binding counter and separator |
||
Line 1,544: | Line 2,003: | ||
} |
} |
||
print(makeList(". "));</ |
print(makeList(". "));</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
Latest revision as of 19:20, 13 July 2024
![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.
- 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 responsible for creating a list item. It accesses the separator from the outer function and modifies the counter.
- References
11l
F makeList(separator)
V counter = 1
F makeItem(item)
-V result = @counter‘’@separator‘’item"\n"
@counter++
R result
R makeItem(‘first’)‘’makeItem(‘second’)‘’makeItem(‘third’)
print(makeList(‘. ’))
- Output:
1. first 2. second 3. third
Ada
with Ada.Text_IO;
procedure Nested_Functions is -- 'Nested_Functions' is the name of 'main'
type List is array(Natural range <>) of String(1 .. 10);
function Make_List(Separator: String) return List is
Counter: Natural := 0;
function Make_Item(Item_Name: String) return String is
begin
Counter := Counter + 1; -- local in Make_List, global in Make_Item
return(Natural'Image(Counter) & Separator & Item_Name);
end Make_Item;
begin
return (Make_Item("First "), Make_Item("Second"), Make_Item("Third "));
end Make_List;
begin -- iterate through the result of Make_List
for Item of Make_List(". ") loop
Ada.Text_IO.Put_Line(Item);
end loop;
end Nested_Functions;
- Output:
$ ./nested_functions 1. First 2. Second 3. Third
68000 Assembly
;program starts here, after loading palettes etc.
MOVE.W #3,D1
MOVE.W #'.',D4
JSR MakeList
jmp * ;halt
MakeList:
MOVE.W #1,D0
loop_MakeList:
MOVE.W D0,-(SP)
JSR PrintHex
MOVE.B D4,D0 ;load separator into D0
JSR PrintChar
MOVE.B #' ',D0
JSR PrintChar
MOVE.W (SP)+,D0
JSR MakeItem
CMP.W D0,D1
BCC loop_MakeList ;back to start
RTS
MakeItem:
MOVE.W D0,D2
SUBQ.W #1,D2
LSL.W #2,D2
LEA PointerToText,A0
MOVE.L (A0,D2),A3
JSR PrintString
JSR NewLine
ADDQ.W #1,D0
RTS
PointerToText:
DC.L FIRST,SECOND,THIRD
FIRST:
DC.B "FIRST",0
EVEN
SECOND:
DC.B "SECOND",0
EVEN
THIRD:
DC.B "THIRD",0
EVEN
- Output:
Also displayed here:
01. FIRST 02. SECOND 03. THIRD
ALGOL 68
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( ". " ) ) )
ALGOL W
Algol W strings are fixed length which makes this slightly more complicated than the Algol 68 solution.
begin
string(30) procedure makeList ( string(2) value separator ) ;
begin
string(30) listValue;
integer counter;
string(10) procedure makeItem ( string(6) value item
; integer value length
) ;
begin
string(10) listItem;
counter := counter + 1;
listItem( 0 // 1 ) := code( decode( "0" ) + counter );
listItem( 1 // 2 ) := separator;
listItem( 3 // 6 ) := item;
listItem( 3 + length // 1 ) := code( 10 );
listItem
end; % makeItem %
counter := 0;
listValue := makeItem( "first", 5 );
listValue( 9 // 10 ) := makeItem( "second", 6 );
listValue( 19 // 10 ) := makeItem( "third", 5 );
listValue
end; % makeList %
write( makeList( ". " ) )
end.
AppleScript
--------------------- NESTED FUNCTION --------------------
-- makeList :: String -> String
on makeList(separator)
set counter to 0
-- makeItem :: String -> String
script makeItem
on |λ|(x)
set counter to counter + 1
(counter & separator & x & linefeed) as string
end |λ|
end script
map(makeItem, ["first", "second", "third"]) as string
end makeList
--------------------------- TEST -------------------------
on run
makeList(". ")
end run
-------------------- GENERIC FUNCTIONS -------------------
-- mReturn :: First-class m => (a -> b) -> m (a -> b)
on mReturn(f)
-- 2nd class handler function lifted into 1st class script wrapper.
if script is class of f then
f
else
script
property |λ| : f
end script
end if
end mReturn
-- map :: (a -> b) -> [a] -> [b]
on map(f, xs)
-- The list obtained by applying f
-- to each element of xs.
tell mReturn(f)
set lng to length of xs
set lst to {}
repeat with i from 1 to lng
set end of lst to |λ|(item i of xs, i, xs)
end repeat
return lst
end tell
end map
- Output:
1. first 2. second 3. third
Note, however, that mutation creates redundant complexity and loss of referential transparency. Functions which modify values outside their own scope are rarely, if ever, necessary, and always best avoided. Simpler and sounder here to derive the incrementing index either by zipping the input list with a range of integers, or by inheriting it from the higher order map function:
-- makeList :: String -> String
on makeList(separator)
-- makeItem :: String -> Int -> String
script makeItem
on |λ|(x, i)
(i & separator & x & linefeed) as string
end |λ|
end script
map(makeItem, ["first", "second", "third"]) as string
end makeList
Arturo
makeList: function [separator][
counter: 1
makeItem: function [item] .export:[counter][
result: ~"|counter||separator||item|"
counter: counter+1
return result
]
@[
makeItem "first"
makeItem "second"
makeItem "third"
]
]
print join.with:"\n" makeList ". "
- Output:
1. first 2. second 3. third
ATS
(* ****** ****** *)
//
#include
"share/atspre_staload.hats"
//
(* ****** ****** *)
fun
MakeList
(
sep: string
) : void = let
//
var count: int = 0
//
val count =
$UNSAFE.cast{ref(int)}(addr@count)
//
fun
MakeItem
(
item: string
) : void = let
val () = !count := !count+1
in
println! (!count, sep, item)
end // end of [MakeItem]
//
in
MakeItem"first"; MakeItem"second"; MakeItem"third"
end // end of [MakeList]
(* ****** ****** *)
implement main0() = { val () = MakeList". " }
(* ****** ****** *)
BQN
MakeList ← {
nl←@+10 ⋄ s←𝕩 ⋄ i←0
MakeItem ← {i+↩1 ⋄ (•Fmt i)∾s∾𝕩}
(⊣∾nl∾⊢)´MakeItem¨"first"‿"second"‿"third"
}
- Output:
MakeList ". " "1. first 2. second 3. third"
C
I honestly never thought this task could ever be done in C and then I was surprised, again. It turns out that nested functions although not a C standard are supported by GCC. I have used anonymous functions in Java and frankly, I don't see any practical benefit other than making code even harder to read. Then again, that's one of the strengths of C. For example, I still have no clue how come the sprintf line is working correctly. I expected the first line of the list to be '1. second', but no, C is C is C.
Not sure who "I" is; but the reason you don't understand the code near sprintf is it's wrong and works by accident. Use of the variable a second time while it's being preincremented has no behavior. Joshudson (talk) 21:33, 3 March 2020 (UTC)JH
IMPORTANT This implementation will only work with GCC. Go through the link above for details.
#include<stdlib.h>
#include<stdio.h>
typedef struct{
char str[30];
}item;
item* makeList(char* separator){
int counter = 0,i;
item* list = (item*)malloc(3*sizeof(item));
item makeItem(){
item holder;
char names[5][10] = {"first","second","third","fourth","fifth"};
sprintf(holder.str,"%d%s%s",++counter,separator,names[counter]);
return holder;
}
for(i=0;i<3;i++)
list[i] = makeItem();
return list;
}
int main()
{
int i;
item* list = makeList(". ");
for(i=0;i<3;i++)
printf("\n%s",list[i].str);
return 0;
}
Output:
1. first 2. second 3. third
C#
string MakeList(string separator)
{
int counter = 1;
Func<string, string> makeItem = item => counter++ + separator + item + "\n";
return makeItem("first") + makeItem("second") + makeItem("third");
}
Console.WriteLine(MakeList(". "));
Update
As of C#7, we can nest actual methods inside other methods instead of creating delegate instances. They can even be declared after the return statement.
string MakeList2(string separator)
{
int counter = 1;
return MakeItem("first") + MakeItem("second") + MakeItem("third");
//using string interpolation
string MakeItem(string item) => $"{counter++}{separator}{item}\n";
}
C++
#include <iostream>
#include <string>
#include <vector>
std::vector<std::string> makeList(std::string separator) {
auto counter = 0;
auto makeItem = [&](std::string item) {
return std::to_string(++counter) + separator + item;
};
return {makeItem("first"), makeItem("second"), makeItem("third")};
}
int main() {
for (auto item : makeList(". "))
std::cout << item << "\n";
}
Clojure
(defn make-list [separator]
(let [x (atom 0)]
(letfn [(make-item [item] (swap! x inc) (println (format "%s%s%s" @x separator item)))]
(make-item "first")
(make-item "second")
(make-item "third"))))
(make-list ". ")
- Output:
1. first 2. second 3. third
Common 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 ". "))
PS: A function named make-list is already defined in Common Lisp, see specification.
Cowgol
include "cowgol.coh";
include "strings.coh";
sub MakeList(sep: [uint8], buf: [uint8]): (out: [uint8]) is
out := buf; # return begin of buffer for ease of use
var counter: uint32 := 0;
# Add item to string
sub AddStr(str: [uint8]) is
var length := StrLen(str);
MemCopy(str, length, buf);
buf := buf + length;
end sub;
sub MakeItem(item: [uint8]) is
counter := counter + 1;
buf := UIToA(counter, 10, buf);
AddStr(sep);
AddStr(item);
AddStr("\n");
end sub;
MakeItem("first");
MakeItem("second");
MakeItem("third");
[buf] := 0; # terminate string
end sub;
var buffer: uint8[100];
print(MakeList(". ", &buffer as [uint8]));
- Output:
1. first 2. second 3. third
D
string makeList(string seperator) {
int counter = 1;
string makeItem(string item) {
import std.conv : to;
return to!string(counter++) ~ seperator ~ item ~ "\n";
}
return makeItem("first") ~ makeItem("second") ~ makeItem("third");
}
void main() {
import std.stdio : writeln;
writeln(makeList(". "));
}
- Output:
1. first 2. second 3. third
Delphi
See Pascal
Ecstasy
module NestedFunction {
static String makeList(String separator) {
Int counter = 1;
function String(String) makeItem = item -> $"{counter++}{separator}{item}\n";
return makeItem("first")
+ makeItem("second")
+ makeItem("third");
}
void run() {
@Inject Console console;
console.print(makeList(". "));
}
}
- Output:
1. first 2. second 3. third
Elena
ELENA 6.x :
import extensions;
MakeList(separator)
{
var counter := 1;
var makeItem := (item){ var retVal := counter.toPrintable() + separator + item + newLineConstant; counter += 1; ^ retVal };
^ makeItem("first") + makeItem("second") + makeItem("third")
}
public program()
{
console.printLine(MakeList(". "))
}
- Output:
1. first 2. second 3. third
Elixir
Elixir data are immutable. Anonymous functions are closures and as such they can access variables that are in scope when the function is defined. Keep in mind a variable assigned inside a function does not affect its surrounding environment:
defmodule Nested do
def makeList(separator) do
counter = 1
makeItem = fn {}, item ->
{"#{counter}#{separator}#{item}\n", counter+1}
{result, counter}, item ->
{result <> "#{counter}#{separator}#{item}\n", counter+1}
end
{} |> makeItem.("first") |> makeItem.("second") |> makeItem.("third") |> elem(0)
end
end
IO.write Nested.makeList(". ")
- Output:
1. first 2. second 3. third
EMal
fun makeList = List by text separator
int counter = 0
fun makeItem = text by text item
return ++counter + separator + item
end
return text[makeItem("first"), makeItem("second"), makeItem("third")]
end
for each text item in makeList(". ") do writeLine(item) end
- Output:
1. first 2. second 3. third
Factor
Words (named functions) cannot be defined with parsing words (such as :
or ::
) in the definition of another word. However, quotations (anonymous functions) can be. We can easily mimic the required behavior by binding a quotation to a lexical variable named make-item
. The only caveat is that we must explicitly call
the quotation in order to execute it.
If we really wanted, we could also define a named word inside make-list
at run time, using words such as define
in the words
vocabulary.
USING: io kernel math math.parser locals qw sequences ;
IN: rosetta-code.nested-functions
:: make-list ( separator -- str )
1 :> counter!
[| item |
counter number>string separator append item append
counter 1 + counter!
] :> make-item
qw{ first second third } [ make-item call ] map "\n" join
;
". " make-list write
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:
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
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 used in 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.
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
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.
Placing all the texts into one "pool" storage area saves space when items are a different length, but items can only be accessed sequentially. If item i
were desired, it can only be found after stepping along from the start and if the collection expands beyond a few dozen items, 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, which can thereby contain any symbol. 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: 8-bits? 16-bits? 32-bits?), so once again, how long is a piece of string?
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.
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
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.
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.
Free Pascal
// In Pascal, functions always _have_ to return _some_ value,
// but the the task doesn’t specify what to return.
// Hence makeList and makeItem became procedures.
procedure makeList(const separator: string);
// The var-section for variables that ought to be accessible
// in the routine’s body as well as the /nested/ routines
// has to appear /before/ the nested routines’ definitions.
var
counter: 1..high(integer);
procedure makeItem;
begin
write(counter, separator);
case counter of
1:
begin
write('first');
end;
2:
begin
write('second');
end;
3:
begin
write('third');
end;
end;
writeLn();
counter := counter + 1;
end;
// You can insert another var-section here, but variables declared
// in this block would _not_ be accessible in the /nested/ routine.
begin
counter := 1;
makeItem;
makeItem;
makeItem;
end;
FreeBASIC
FreeBASIC does not currently support either nested procedures or lambda expressions. The best we can do here is to create two separate procedures but pass the state of the first procedure by reference to the second procedure so it can be modified by the latter.
' FB 1.05.0 Win64
Sub makeItem(sep As String, ByRef counter As Integer, text As String)
counter += 1
Print counter; sep; text
End Sub
Sub makeList(sep As String)
Dim a(0 To 2) As String = {"first", "second", "third"}
Dim counter As Integer = 0
While counter < 3
makeItem(sep, counter, a(counter))
Wend
End Sub
makeList ". "
Print
Print "Press any key to quit"
Sleep
- Output:
1. first 2. second 3. third
Fōrmulæ
Fōrmulæ programs are not textual, visualization/edition of programs is done showing/manipulating structures but not text. Moreover, there can be multiple visual representations of the same program. Even though it is possible to have textual representation —i.e. XML, JSON— they are intended for storage and transfer purposes more than visualization and edition.
Programs in Fōrmulæ are created/edited online in its website.
In this page you can see and run the program(s) related to this task and their results. You can also change either the programs or the parameters they are called with, for experimentation, but remember that these programs were created with the main purpose of showing a clear solution of the task, and they generally lack any kind of validation.
Solution
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(". "))
}
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 ". "
Or, importing a little less heavy machinery:
makeList :: String -> String
makeList separator =
let makeItem = (<>) . (<> separator) . show
in unlines $ zipWith makeItem [1 ..] ["First", "Second", "Third"]
main :: IO ()
main = putStrLn $ makeList ". "
or perhaps:
makeList :: String -> String
makeList separator =
let makeItem = unlines . zipWith ((<>) . (<> separator) . show) [1..]
in makeItem ["First", "Second", "Third"]
main :: IO ()
main = putStrLn $ makeList ". "
- Output:
1. First 2. Second 3. Third
Io
makeList := method(separator,
counter := 1
makeItem := method(item,
result := counter .. separator .. item .. "\n"
counter = counter + 1
result
)
makeItem("first") .. makeItem("second") .. makeItem("third")
)
makeList(". ") print
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:
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
)
Example use:
'. ' MakeList 'first';'second';'third'
1. first
2. second
3. third
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.
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(". "));
}
}
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(". "));
jq
def makeList(separator):
# input: {text: _, counter: _}
def makeItem(item):
(.counter + 1) as $counter
| .text += "\($counter)\(separator)\(item)\n"
| .counter = $counter;
{text:"", counter:0} | makeItem("first") | makeItem("second") | makeItem("third")
| .text
;
makeList(". ")
With the above in a file, say program.jq, the invocation:
$ jq -n -r -f program.jq
produces:
1. first 2. second 3. third
Jsish
From Javascript entry.
/* Nested function, in Jsish */
function makeList(separator) {
var counter = 1;
function makeItem(item) {
return counter++ + separator + item + "\n";
}
return makeItem("first") + makeItem("second") + makeItem("third");
}
;makeList('. ');
/*
=!EXPECTSTART!=
makeList('. ') ==> 1. first
2. second
3. third
=!EXPECTEND!=
*/
- Output:
prompt$ jsish -u nestedFunction.jsi [PASS] nestedFunction.jsi
Julia
function makelist(sep::String)
cnt = 1
function makeitem(item::String)
rst = string(cnt, sep, item, '\n')
cnt += 1
return rst
end
return makeitem("first") * makeitem("second") * makeitem("third")
end
print(makelist(". "))
Kotlin
// version 1.0.6
fun makeList(sep: String): String {
var count = 0
fun makeItem(item: String): String {
count++
return "$count$sep$item\n"
}
return makeItem("first") + makeItem("second") + makeItem("third")
}
fun main(args: Array<String>) {
print(makeList(". "))
}
- Output:
1. first 2. second 3. third
Lambdatalk
Lambdatalk has neither closures nor states but we can do that, thanks to mutability of arrays behaving as "sandbox" of mutability.
{def makeList
{def makeItem
{lambda {:s :a :i}
{div}{A.first {A.set! 0 {+ {A.first :a} 1} :a}}:s :i}}
{lambda {:s}
{S.map {{lambda {:s :a :i} {makeItem :s :a :i}}
:s {A.new 0}}
first second third
}}}
-> makeList
{makeList .}
->
1. first
2. second
3. third
Lua
function makeList (separator)
local counter = 0
local function makeItem(item)
counter = counter + 1
return counter .. separator .. item .. "\n"
end
return makeItem("first") .. makeItem("second") .. makeItem("third")
end
print(makeList(". "))
- Output:
1. first 2. second 3. third
M2000 Interpreter
In M2000 functions may have functions, modules, subs, but these are black boxes. We can define globals for temporary use. Subs can use anything from module/function where we call them. First example use Subs inside a module, when call Make_list two local variables, Separator$ and Counter allocated in same space as module's. So when we call Make_item() these variables are visible. At the exit of sub Make_list local variables destroyed. In second example Letter$ pop a string from stack of values (or an error raised if no string found).
Module Checkit {
Make_List(". ")
Sub Make_List(Separator$)
Local Counter=0
Make_Item("First")
Make_Item("Second")
Make_Item("Third")
End Sub
Sub Make_Item(Item_Name$)
Counter++
Print Str$(Counter,"")+Separator$+Item_Name$
End Sub
}
Checkit
Module Make_List {
Global Counter=0, Separator$=Letter$
Make_Item("First")
Make_Item("Second")
Make_Item("Third")
Sub Make_Item(Item_Name$)
Counter++
Print Str$(Counter,"")+Separator$+Item_Name$
End Sub
}
Make_List ". "
Module Make_List1 {
Global Counter=0, Separator$=Letter$
Module Make_Item (Item_Name$) {
Counter++
Print Str$(Counter,"")+Separator$+Item_Name$
}
Make_Item "First"
Make_Item "Second"
Make_Item "Third"
}
Make_List1 ". "
Module Make_List (Separator$) {
Def Counter as Integer
// Need New before Item_Name$, because the scope is the module scope
// the scope defined from the calling method.
// by default a function has a new namespace.
Function Make_Item(New Item_Name$){
Counter++
Print Str$(Counter,"")+Separator$+Item_Name$
}
// Call Local place the module scope to function
// function called like a module
Call Local Make_Item("First")
Call Local Make_Item("Second")
Call Local Make_Item("Third")
Print "Counter=";Counter // 3
}
Make_List ". "
Module Make_List (Separator$) {
Def Counter
// using Module not Function.
Module Make_Item(New Item_Name$){
Counter++
Print Str$(Counter,"")+Separator$+Item_Name$
}
Call Local Make_Item,"First"
Call Local Make_Item,"Second"
Call Local Make_Item,"Third"
Print "Counter=";Counter // 3
}
Make_List ". "
Maple
makelist:=proc()
local makeitem,i;
i:=1;
makeitem:=proc(i)
if i=1 then
printf("%a\n", "1. first");
elif i=2 then
printf("%a\n","2. second");
elif i=3 then
printf("%a\n", "3. third");
else
return NULL;
end if;
end proc;
while i<4 do
makeitem(i);
i:=i+1;
end do;
end proc;
Mathematica /Wolfram Language
makeList[sep_String]:=Block[
{counter=0, makeItem},
makeItem[item_String]:=ToString[++counter]<>sep<>item;
makeItem /@ {"first", "second", "third"}
]
Scan[Print, makeList[". "]]
min
Note the @
sigil is the key to altering counter
in the outer scope.
(
:separator
1 :counter
(
:item
item separator counter string ' append append "" join
counter succ @counter
) :make-item
("first" "second" "third") 'make-item map "\n" join
) :make-list
". " make-list print
MiniScript
Subfunctions can directly read variables in the enclosing scope, but to assign to those variables, they must explicitly use the outer specifier (added in MiniScript version 1.5). This is similar to how global variables are accessed via globals.
makeList = function(sep)
counter = 0
makeItem = function(item)
outer.counter = counter + 1
return counter + sep + item
end function
return [makeItem("first"), makeItem("second"), makeItem("third")]
end function
print makeList(". ")
Output:
["1. first", "2. second", "3. third"]
Nanoquery
def makeList(separator)
counter = 1
def makeItem(item)
result = str(counter) + separator + item + "\n"
counter += 1
return result
end
return makeItem("first") + makeItem("second") + makeItem("third")
end
println makeList(". ")
Nim
proc makeList(separator: string): string =
var counter = 1
proc makeItem(item: string): string =
result = $counter & separator & item & "\n"
inc counter
makeItem("first") & makeItem("second") & makeItem("third")
echo $makeList(". ")
- Output:
1. first 2. second 3. third
Objective-C
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;
}
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 ". ")
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
Pascal
See Free Pascal
PascalABC.NET
procedure MakeList(separator: string);
var counter := 1;
procedure MakeItem;
begin
Write(counter, separator);
case counter of
1: Writeln('first');
2: Writeln('second');
3: Writeln('third');
end;
counter += 1;
end;
begin
MakeItem;
MakeItem;
MakeItem;
end;
begin
MakeList('. ');
end.
- Output:
1. first 2. second 3. third
Perl
sub makeList {
my $separator = shift;
my $counter = 1;
sub makeItem { $counter++ . $separator . shift . "\n" }
makeItem("first") . makeItem("second") . makeItem("third")
}
print makeList(". ");
Phix
There is only partial support for nested functions in Phix. Some prior work (over a single afternoon) has been left
unfinished, anyone interested can see it at Nested_function/Phix, but it was just enough to open the door for
the two following reasonably acceptable work-arounds.
Note that in both the following you cannot reference any local variables or parameters of the containing function,
but must pass in everything you need explicitly, and anything you need to update must be a reference type, which
is only dictionaries and class instances, not integers, atoms, sequences, strings, or any user-defined types, as
they are all effectively read-only. Referring to identifiers in the containing/outer function issues proper errors
in 1.0.0 and later, prior to that it simply won't work as hoped for.
using a dictionary
function MakeList(string sep=". ")
function MakeItem(integer env, string sep)
integer counter = getd("counter",env)+1
setd("counter",counter,env)
return sprintf("%d%s%s",{counter,sep,{"first","second","third"}[counter]})
end function
integer counter = new_dict({{"counter",0}})
sequence res = {}
for i=1 to 3 do
res = append(res,MakeItem(counter,sep))
end for
return res
end function
?MakeList()
- Output:
{"1. first","2. second","3. third"}
using a class
Same output. I trust it is obvious that if you passed in c.count, you would not be able to update it.
Again note how MakeList's sep must be explicitly re-passed to MakeItem.
Also note that the counter class cannot be made private to MakeList, however as a non-global it would automatically be private to a single source code file.
class counter
public integer count
end class
function MakeList(string sep=". ")
function MakeItem(counter c, string sep)
c.count += 1
return sprintf("%d%s%s",{c.count,sep,{"first","second","third"}[c.count]})
end function
counter c = new()
sequence res = {}
for i=1 to 3 do
res = append(res,MakeItem(c,sep))
end for
return res
end function
?MakeList()
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(". ");
?>
PicoLisp
(de makeList (Sep)
(let (Cnt 0 makeItem '((Str) (prinl (inc 'Cnt) Sep Str)))
(makeItem "first")
(makeItem "second")
(makeItem "third") ) )
(makeList ". ")
PL/M
In CP/M and by convention in PL/M, strings are terminated by $.
Note the original 8080 PL/M compiler treats lower case letters as spaces in the source, so the list is in upper case in this sample.
100H: /* USE A NESTED PROCEDURE TO CONSTRUCT A STRING, UPDATING VARIABLES IN */
/* THE CONTAINING PROCEDURE */
/* CP/M BDOS SYSTEM CALL */
BDOS: PROCEDURE( FN, ARG ); DECLARE FN BYTE, ARG ADDRESS; GOTO 5;END;
/* CONSOLE OUTPUT ROUTINES */
PR$STRING: PROCEDURE( S ); DECLARE S ADDRESS; CALL BDOS( 9, S ); END;
/* CONCATENATES ITEM TO THE END OF STR. STR MUST BE LONG ENOUGH TO HOLD */
/* THE CONCATENATED VALUE */
CONCAT: PROCEDURE( STR, ITEM );
DECLARE ( STR, ITEM ) ADDRESS;
DECLARE STR$S BASED STR ( 0 )BYTE;
DECLARE ITEM$S BASED ITEM ( 0 )BYTE;
DECLARE ( STR$POS, ITEM$POS ) BYTE;
/* FIND THE CURRENT END OF STR */
STR$POS = 0;
DO WHILE STR$S( STR$POS ) <> '$';
STR$POS = STR$POS + 1;
END;
/* COPY ITEM TO THE END OF STR */
ITEM$POS = 0;
DO WHILE ITEM$S( ITEM$POS ) <> '$';
STR$S( STR$POS ) = ITEM$S( ITEM$POS );
ITEM$POS = ITEM$POS + 1;
STR$POS = STR$POS + 1;
END;
STR$S( STR$POS ) = '$';
END CONCAT ;
/* TASK */
/* RETURNS THE ADDRESS OF A STRING CONCATENATED FROM CALLS TO THE NESTED */
/* MAKE$ITEM PROCEDURE - THE RESULTANT STRING MUST NOT BE MORE */
/* THAN 64 CHARACTERS IN LENGTH */
MAKE$LIST: PROCEDURE( SEPARATOR )ADDRESS;
DECLARE SEPARATOR ADDRESS;
DECLARE LIST$VALUE ( 65 )BYTE;
DECLARE COUNTER BYTE;
/* RETURNS THE ADDRESS OF A LIST ITEM, THE LENGTH OF THE ITEM MUST'NT */
/* BE MORE THAN 32 CHARACTERS */
MAKE$ITEM: PROCEDURE( ITEM )ADDRESS;
DECLARE ITEM ADDRESS;
DECLARE LIST$ITEM ( 33 )BYTE;
COUNTER = COUNTER + 1;
LIST$ITEM( 0 ) = '0' + COUNTER;
LIST$ITEM( 1 ) = '$';
CALL CONCAT( .LIST$ITEM, SEPARATOR );
CALL CONCAT( .LIST$ITEM, ITEM );
CALL CONCAT( .LIST$ITEM, .( 0DH, 0AH, '$' ) );
RETURN .LIST$ITEM;
END MAKE$ITEM ;
COUNTER = 0;
LIST$VALUE( 0 ) = '$';
CALL CONCAT( .LISTVALUE, MAKE$ITEM( .'FIRST$' ) );
CALL CONCAT( .LISTVALUE, MAKE$ITEM( .'SECOND$' ) );
CALL CONCAT( .LISTVALUE, MAKE$ITEM( .'THIRD$' ) );
RETURN .LIST$VALUE;
END MAKE$LIST ;
CALL PR$STRING( MAKE$LIST( .'. $' ) );
EOF
- Output:
1. FIRST 2. SECOND 3. THIRD
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(". "))
R
This also shows that cat's sep argument is not the same as MakeList's.
MakeList <- function(sep)
{
counter <- 0
MakeItem <- function() paste0(counter <<- counter + 1, sep, c("first", "second", "third")[counter])
cat(replicate(3, MakeItem()), sep = "\n")
}
MakeList(". ")
- Output:
1. first 2. second 3. third
Racket
See also #Scheme; this demonstrates map
a higher order function and begin0
a form which saves us having to explicitly remember the result.
#lang racket
(define (make-list separator)
(define counter 1)
(define (make-item item)
(begin0
(format "~a~a~a~%" counter separator item)
(set! counter (add1 counter))))
(apply string-append (map make-item '(first second third))))
(display (make-list ". "))
- Output:
1. first 2. second 3. third
Raku
(formerly Perl 6)
sub make-List ($separator = ') '){
my $count = 1;
sub make-Item ($item) { "{$count++}$separator$item" }
join "\n", <first second third>».&make-Item;
}
put make-List('. ');
- Output:
1. first 2. second 3. third
REXX
This REXX version is modeled after the FreeBASIC example (and it has the same limitations).
/*REXX program demonstrates that functions can be nested (an outer and inner function).*/
ctr= 0 /*initialize the CTR REXX variable.*/
call MakeList '. ' /*invoke MakeList with the separator.*/
exit 0 /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
MakeItem: parse arg sep,text; ctr= ctr + 1 /*bump the counter variable. */
say ctr || sep || word($, ctr) /*display three thingys ───► terminal. */
return
/*──────────────────────────────────────────────────────────────────────────────────────*/
MakeList: parse arg sep; $= 'first second third' /*obtain an argument; define a string.*/
do while ctr<3 /*keep truckin' until finished. */
call MakeItem sep, $ /*invoke the MakeItem function. */
end /*while*/
return
- output when using the default input:
1. first 2. second 3. third
Ring
# Project : Nested function
makeList(". ")
func makeitem(sep, counter, text)
see "" + counter + sep + text + nl
func makelist(sep)
a = ["first", "second", "third"]
counter = 0
while counter < 3
counter = counter + 1
makeitem(sep, counter, a[counter])
end
Output:
1. first 2. second 3. third
RPL
Fully compliant
The outer function creates the inner function, then deletes it at its last execution step.
The \n
substring must be replaced by a Newline
character when typing the code.
≪ ≪ + OVER →STR SWAP + ROT SWAP + SWAP 1 + ≫ 'MakeItem' STO "" 1 3 PICK "first\n" MakeItem 3 PICK "second\n" MakeItem 3 PICK "third\n" MakeItem DROP SWAP DROP 'MakeItem' PURGE ≫ ‘MakeList’ STO
". " MakeList
- Output:
1: "1. first 2. second 3. third"
Unnamed nested functions
It is more idiomatic in RPL to use unnamed nested functions, which allows the use of local variables and then increases code readability.
≪ "" 1 1 3 FOR j 3 PICK { "first\n" "second\n" "third\n" } j GET → sep item ≪ DUP →STR sep + item + ROT SWAP + SWAP 1 + ≫ NEXT DROP SWAP DROP ≫
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(". ")
Rust
fn make_list(sep: &str) -> String {
let mut counter = 0;
let mut make_item = |label| {
counter += 1;
format!("{}{}{}", counter, sep, label)
};
format!(
"{}\n{}\n{}",
make_item("First"),
make_item("Second"),
make_item("Third")
)
}
fn main() {
println!("{}", make_list(". "))
}
- Output:
1. First 2. Second 3. Third
Scala
def main(args: Array[String]) {
val sep: String=". "
var c:Int=1;
def go(s: String):Unit={
println(c+sep+s)
c=c+1
}
go("first")
go("second")
go("third")
}
- Output:
1. first 2. second 3. third
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 ". "))
Seed7
$ include "seed7_05.s7i";
const func string: makeList (in string: separator) is func
result
var string: itemList is "";
local
var integer: counter is 1;
const func string: makeItem (in string: item) is func
result
var string: anItem is "";
begin
anItem := counter <& separator <& item <& "\n";
incr(counter);
end func
begin
itemList := makeItem("first") & makeItem("second") & makeItem("third");
end func;
const proc: main is func
begin
write(makeList(". "));
end func;
- Output:
1. first 2. second 3. third
Sidef
func make_list(separator = ') ') {
var count = 1
func make_item(item) {
[count++, separator, item].join
}
<first second third>.map(make_item).join("\n")
}
say make_list('. ')
- Output:
1. first 2. second 3. third
Simula
COMMENT CLASS SIMSET IS SIMULA'S STANDARD LINKED LIST DATA TYPE
CLASS HEAD IS THE LIST ITSELF
CLASS LINK IS THE ELEMENT OF A LIST
PROCEDURE IS THE TERM USED FOR FUNCTIONS IN SIMULA
TEXT IS THE TERM USED FOR STRINGS IN SIMULA ;
SIMSET
BEGIN
LINK CLASS ITEM(TXT); TEXT TXT;;
COMMENT CREATING THE LIST AS A WHOLE WITH THE SEPARATOR ". "
GIVEN AS AN ARGUMENT;
REF(HEAD) PROCEDURE MAKELIST(SEPARATOR); TEXT SEPARATOR;
BEGIN
COMMENT VARIABLE TO KEEP TRACK OF THE ITEM NUMBER ;
INTEGER COUNTER;
COMMENT THIS IS THE NESTED FUNCTION ;
REF(ITEM) PROCEDURE MAKEITEM(TXT); TEXT TXT;
BEGIN
TEXT NUM;
TEXT ITEMTEXT;
COMMENT CONVERT NUMBER TO STRING ;
NUM :- BLANKS(5);
NUM.PUTINT(COUNTER);
COMMENT ACCESS SEPARATOR AND MODIFY COUNTER;
COUNTER := COUNTER + 1;
ITEMTEXT :- NUM & SEPARATOR & TXT;
MAKEITEM :- NEW ITEM(ITEMTEXT);
END MAKEITEM;
REF(HEAD) HD;
HD :- NEW HEAD;
COUNTER := 1;
MAKEITEM("FIRST").INTO(HD);
MAKEITEM("SECOND").INTO(HD);
MAKEITEM("THIRD").INTO(HD);
MAKELIST :- HD;
END MAKELIST;
REF(HEAD) LIST;
REF(ITEM) IT;
LIST :- MAKELIST(". ");
COMMENT NAVIGATE THROUGH THE LIST ;
IT :- LIST.FIRST;
WHILE IT =/= NONE DO
BEGIN
OUTTEXT(IT.TXT);
OUTIMAGE;
IT :- IT.SUC;
END;
END.
- Output:
1. FIRST 2. SECOND 3. THIRD
Standard ML
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 ". ")
SuperCollider
(
f = { |separator|
var count = 0;
var counting = { |name|
count = count + 1;
count.asString ++ separator + name ++ "\n"
};
counting.("first") + counting.("second") + counting.("third")
};
)
f.(".")
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(". "))
Tcl
The code below satisfies the specification (inspired by the Swift example). The inner function MakeItem (which gains read/write access to its caller's variables via upvar) is defined, called, and then discarded by renaming to {}. suchenwi
#!/usr/bin/env tclsh
proc MakeList separator {
set counter 1
proc MakeItem string {
upvar 1 separator separator counter counter
set res $counter$separator$string\n
incr counter
return $res
}
set res [MakeItem first][MakeItem second][MakeItem third]
rename MakeItem {}
return $res
}
puts [MakeList ". "]
VBA
Option Explicit
Private Const Sep As String = ". "
Private Counter As Integer
Sub Main()
Dim L As Variant
Counter = 0
L = MakeList(Array("first", "second", "third"))
Debug.Print L
End Sub
Function MakeList(Datas) As Variant
Dim i As Integer
For i = LBound(Datas) To UBound(Datas)
MakeList = MakeList & MakeItem(Datas(i))
Next i
End Function
Function MakeItem(Item As Variant) As Variant
Counter = Counter + 1
MakeItem = Counter & Sep & Item & vbCrLf
End Function
- Output:
1. first 2. second 3. third
Wren
var makeList = Fn.new { |sep|
var counter = 0
var makeItem = Fn.new { |name|
counter = counter + 1
return "%(counter)%(sep)%(name)"
}
var items = []
for (name in ["first", "second", "third"]) {
items.add(makeItem.call(name))
}
System.print(items.join("\n"))
}
makeList.call(". ")
- Output:
1. first 2. second 3. third
XPL0
proc MakeList(Separator);
char Separator;
int Counter;
proc MakeItem;
int Ordinals;
[IntOut(0, Counter);
Text(0, Separator);
Ordinals:= [0, "first", "second", "third"];
Text(0, Ordinals(Counter));
CrLf(0);
];
for Counter:= 1 to 3 do MakeItem; \MakeList procedure
MakeList(". ") \main procedure
- Output:
1. first 2. second 3. third
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.
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(". "));
- Output:
1. first 2. second 3. third
- Programming Tasks
- Solutions by Programming Task
- Scope
- Functions and subroutines
- 11l
- Ada
- 68000 Assembly
- ALGOL 68
- ALGOL W
- AppleScript
- Arturo
- ATS
- BQN
- C
- C sharp
- C++
- Clojure
- Common Lisp
- Cowgol
- D
- Delphi
- Ecstasy
- Elena
- Elixir
- EMal
- Factor
- Fortran
- Free Pascal
- FreeBASIC
- Fōrmulæ
- Go
- Haskell
- Io
- J
- Java
- JavaScript
- Jq
- Jsish
- Julia
- Kotlin
- Lambdatalk
- Lua
- M2000 Interpreter
- Maple
- Mathematica
- Wolfram Language
- Min
- MiniScript
- Nanoquery
- Nim
- Objective-C
- OCaml
- Pascal
- PascalABC.NET
- Perl
- Phix
- Phix/Class
- PHP
- PicoLisp
- PL/M
- Python
- R
- Racket
- Raku
- REXX
- Ring
- RPL
- Ruby
- Rust
- Scala
- Scheme
- Seed7
- Sidef
- Simula
- Standard ML
- SuperCollider
- Swift
- Tcl
- VBA
- Wren
- XPL0
- Zkl