Open main menu
Home
Random
Recent changes
Special pages
Community portal
Preferences
About Wikipedia
Disclaimers
Incubator escapee wiki
Search
User menu
Talk
Dark mode
Contributions
Create account
Log in
Editing
Icon (programming language)
(section)
Warning:
You are not logged in. Your IP address will be publicly visible if you make any edits. If you
log in
or
create an account
, your edits will be attributed to your username, along with other benefits.
Anti-spam check. Do
not
fill this in!
===Generators=== Expressions in Icon may return a single value, for instance, {{code|5 > x}} will evaluate and return x if the value of x is less than 5, otherwise it will fail and return no value. Icon also includes the concept of procedures that do not ''immediately'' return success or failure, and instead return new values every time they are called. These are known as [[generator (computer programming)|''generators'']], and are a key part of the Icon language. Within the parlance of Icon, the evaluation of an expression or function produces a ''result sequence''. A result sequence contains all the possible values that can be generated by the expression or function. When the result sequence is exhausted, the expression or function fails. Icon allows any procedure to return a single value or multiple values, controlled using the {{code|fail}}, {{code|return}} and {{code|suspend}} keywords. A procedure that lacks any of these keywords returns {{code|&fail}}, which occurs whenever execution runs to the {{code|end}} of a procedure. For instance: <syntaxhighlight lang="icon"> procedure f(x) if x > 0 then { return 1 } end </syntaxhighlight> Calling {{code|f(5)}} will return 1, but calling {{code|f(-1)}} will return {{code|&fail}}. This can lead to non-obvious behavior, for instance, {{code|write(f(-1))}} will output nothing because {{code|f}} fails and suspends operation of {{code|write}}.{{sfn|Tratt|2010|p=75}} Converting a procedure to be a generator uses the {{code|suspend}} keyword, which means "return this value, and when called again, start execution at this point". In this respect it is something like a combination of the [[Static (keyword)|{{code|static}}]] concept in C and {{code|return}}. For instance:{{sfn|Tratt|2010|p=74}} <syntaxhighlight lang="icon"> procedure ItoJ(i, j) while i <= j do { suspend i i +:= 1 } fail end </syntaxhighlight> creates a generator that returns a series of numbers starting at {{code|i}} and ending a {{code|j}}, and then returns {{code|&fail}} after that.{{efn|The {{code|fail}} is not ''required'' in this case as it is immediately before the {{code|end}}. It has been added for clarity.}} The {{code|suspend i}} stops execution and returns the value of {{code|i}} without reseting any of the state. When another call is made to the same function, execution picks up at that point with the previous values. In this case, that causes it to perform {{code|i +:{{=}} 1}}, loop back to the start of the while block, and then return the next value and suspend again. This continues until {{code|i <{{=}} j}} fails, at which point it exits the block and calls {{code|fail}}. This allows [[iterator]]s to be constructed with ease.{{sfn|Tratt|2010|p=74}} Another type of generator-builder is the ''alternator'', which looks and operates like the Boolean {{code|or}} operator. For instance: <syntaxhighlight lang="icon"> if y < (x | 5) then write("y=", y) </syntaxhighlight> This appears to say "if y is smaller than x or 5 then...", but is actually a short-form for a generator that returns values until it falls off the end of the list. The values of the list are "injected" into the operations, in this case, {{code|<}}. So in this example, the system first tests y < x, if x is indeed larger than y it returns the value of x, the test passes, and the value of y is written out in the {{code|then}} clause. However, if x is not larger than y it fails, and the alternator continues, performing y < 5. If that test passes, y is written. If y is smaller than neither x or 5, the alternator runs out of tests and fails, the {{code|if}} fails, and the {{code|write}} is not performed. Thus, the value of y will appear on the console if it is smaller than x or 5, thereby fulfilling the purpose of a Boolean {{code|or}}. Functions will not be called unless evaluating their parameters succeeds, so this example can be shortened to: <syntaxhighlight lang="icon"> write("y=", (x | 5) > y) </syntaxhighlight> Internally, the alternator is not simply an {{code|or}} and one can also use it to construct arbitrary lists of values. This can be used to iterate over arbitrary values, like: <syntaxhighlight lang="icon"> every i := (1|3|4|5|10|11|23) do write(i) </syntaxhighlight> As lists of integers are commonly found in many programming contexts, Icon also includes the {{code|to}} keyword to construct ''ad hoc'' integer generators: <syntaxhighlight lang="icon"> every k := i to j do write(k) </syntaxhighlight> which can be shortened: <syntaxhighlight lang="icon"> every write(1 to 10) </syntaxhighlight> Icon is not strongly typed, so the alternator lists can contain different types of items: <syntaxhighlight lang="icon"> every i := (1 | "hello" | x < 5) do write(i) </syntaxhighlight> This writes 1, "hello" and maybe 5 depending on the value of x. Likewise the ''conjunction operator'', {{code|&}}, is used in a fashion similar to a Boolean {{code|and}} operator:{{sfn|Tratt|2010|p=76}} <syntaxhighlight lang="icon"> every x := ItoJ(0,10) & x % 2 == 0 do write(x) </syntaxhighlight> This code calls {{code|ItoJ}} and returns an initial value of 0 which is assigned to x. It then performs the right-hand side of the conjunction, and since {{code|x % 2}} does equal 0, it writes out the value. It then calls the {{code|ItoJ}} generator again which assigns 1 to x, which fails the right-hand-side and prints nothing. The result is a list of every even integer from 0 to 10.{{sfn|Tratt|2010|p=76}} The concept of generators is particularly useful and powerful when used with string operations, and is a major underlying basis for Icon's overall design. Consider the {{code|indexOf}} operation found in many languages; this function looks for one string within another and returns an index of its location, or a magic number if it is not found. For instance: <syntaxhighlight lang="java"> s = "All the world's a stage. And all the men and women merely players"; i = indexOf("the", s); write(i); </syntaxhighlight> This will scan the string {{code|s}}, find the first occurrence of "the", and return that index, in this case 4. The string, however, contains two instances of the string "the", so to return the second example an alternate syntax is used: <syntaxhighlight lang="java"> j = indexOf("the", s, i+1); write(j); </syntaxhighlight> This tells it to scan starting at location 5, so it will not match the first instance we found previously. However, there may not be a second instance of "the" -there may not be a first one either- so the return value from {{code|indexOf}} has to be checked against the magic number -1 which is used to indicate no matches. A complete routine that prints out the location of every instance is: <syntaxhighlight lang="java"> s = "All the world's a stage. And all the men and women merely players"; i = indexOf("the", s); while i != -1 { write(i); i = indexOf("the", s, i+1); } </syntaxhighlight> In Icon, the equivalent {{code|find}} is a generator, so the same results can be created with a single line: <syntaxhighlight lang="icon"> s := "All the world's a stage. And all the men and women merely players" every write(find("the", s)) </syntaxhighlight> Of course there are times where one does want to find a string after some point in input, for instance, if scanning a text file that contains a line number in the first four columns, a space, and then a line of text. Goal-directed execution can be used to skip over the line numbers: <syntaxhighlight lang="icon"> every write(5 < find("the", s)) </syntaxhighlight> The position will only be returned if "the" appears after position 5; the comparison will fail otherwise, pass the fail to write, and the write will not occur. The {{code|every}} operator is similar to {{code|while}}, looping through every item returned by a generator and exiting on failure:{{sfn|Tratt|2010|p=75}} <syntaxhighlight lang="icon"> every k := i to j do write(someFunction(k)) </syntaxhighlight> There is a key difference between {{code|every}} and {{code|while}}; {{code|while}} re-evaluates the first result until it fails, whereas {{code|every}} fetches the next value from a generator. {{code|every}} actually injects values into the function in a fashion similar to blocks under [[Smalltalk]]. For instance, the above loop can be re-written this way:{{sfn|Tratt|2010|p=75}} <syntaxhighlight lang="icon"> every write(someFunction(i to j)) </syntaxhighlight> In this case, the values from i to j will be injected into {{code|someFunction}} and (potentially) write multiple lines of output.{{sfn|Tratt|2010|p=75}}
Edit summary
(Briefly describe your changes)
By publishing changes, you agree to the
Terms of Use
, and you irrevocably agree to release your contribution under the
CC BY-SA 4.0 License
and the
GFDL
. You agree that a hyperlink or URL is sufficient attribution under the Creative Commons license.
Cancel
Editing help
(opens in new window)