Icon+Unicon/Intro: Difference between revisions

(→‎Contractions: + extreme)
Line 617:
Here is another example taken from [[Sierpinski_carpet|Sierpinski Carpet]] which we will explain:
 
The procedure IsFilled is used to determine if the carpet is to be filled. and The original version is a fairly straightforward translation of Java which in turn was translated from Python. About the only natural contraction for the language is the use of the fact that operators return values and comparisons can be chained.<lang Icon>procedure IsFilled(x,y)
while x ~= 0 & y ~= 0 do {
if x % 3 = y %3 = 1 then fail
Line 626:
end</lang>
 
Taken to extremes we can write the following:<lang Icon>procedure IsFilled2IsFilled(x,y)
every | (x(1 *:= x % 3, = y *:=%3 3,& break)) |((1 = (x /:= 3) %& 3 = (y /:= 3) %3,fail)|next)) | return
end</lang>
 
How did we get to this point:
* You can convert ''while'' loops into ''every'' loops with unary alternation (| expr)
* every proceeds evaluating expressions until a result can generate more values via alternation (x|y) or (|expr), generation (!x), or generators. Everything before the (|x) is evaluated only once. So this example initializes by multiplying x and y by 3 before iterating and reducing them by 3 each loop. Reduction by 3 and modulus checking are all within a single expression that if successful fails the procedure.
* The first expression needs to cause procedure failure when x and y mod 3 are both 1. Using break exits the loop and fails by default at the end of the procedure.
* "every expr | return" removes a line break
* The second alternate expression divides x and y by 3 for the next iteration. This expression always succeeds and the loop continues. While there is nothing wrong with its position here, the construction is somewhat misleading.
* The last alternative succeeds ending the procedure. Often ending an every in "| return" is a bit of a cheap trick to save a line. However, here it works because we need the implicit failure at ''end''.
 
The above is a fairly elegant if somewhat extreme example of a contraction. A somewhat more intuitive version might be:<lang Icon>procedure IsFilled(x,y)
every | (1 = x % 3 = y %3, break) | return do
x /:= 3 & y /:= 3
end</lang>
 
And lastly a contrived and somewhat grotesque version:
<lang Icon>procedure IsFilled(x,y)
every (x *:= 3, y *:= 3, | (x /:= 3, y /:= 3,(x % 3 = y %3 = 1, break))) | return
end</lang>
... in which the conditional failure is moved to the bottom of the loop. The leading expressions are only evaluated once as the generated looping doesn't begin until the alternation operator. Now it's fairly common to need to initialize a variable at the beginning of a loop. This can be easily done with every, but it becomes a bit strained when performing multiple initializations.
 
= Run Time Considerations =
Anonymous user