W Wrapl, The Programming Language

Chapter 3

Success and Failure

Unlike in most other languages, (Icon being the main exception), expressions in Wrapl do not simply evaluate to a single result. Instead, they may succeed in producing one or more results, or fail to produce any result. For example, the expression 10 can only produce a single value, 10, whereas the expression 10 | 20 can produce the value 10, followed by the value 20. The special expression BACK fails to produce any value. The expression ALL expr returns a list of all the values produced by expr.

--> 10; 10 --> 10 | 20; 10 --> BACK; failure --> ALL 10; [10] --> ALL 10 | 20; [10, 20] --> ALL BACK; []

Backtracking

In general, an expression will only produce one value. However, if a later part in the same expression fails, then the earlier expression may be resumed and produce another value. If this happens, then evaluation continues after the resumed expression. If no earlier expression can be resumed, the entire expression fails. For example, the comparison operators in Wrapl do not return true or false, instead they succeed and return the second argument if the comparison is true, and fail if it is false.

--> 10 < 20; 20 --> 10 > 20; failure --> 10 < (5 | 15); 15 -> 10 > (5 | 15); 5

Flow Control

This success/failure of expressions can be used in conditional expressions to control program flow similar to if-statements in other languages. A conditional expression looks like cond => expr1 // expr2, and returns the values produced by expr1 if cond succeeds and the values produced by expr2 if cond fails. Either => expr1 or // expr2 may be omitted, in which case BACK is used instead.

--> 1 => 2 // 3; 2 --> BACK => 2 // 3; 3 --> (1 < 2) => 3; 3 --> (1 > 2) => 3; failure --> (1 < 2) // 3; failure --> (1 > 2) // 3; 3

Generators

There are several expressions in Wrapl that will produce more than one value. The expression expr1 | expr2 produces all the values produced by expr1 followed by all the values produced by expr2. The method :to(from, limit) produces all the numbers from from to limit in increments of 1. The method :to(from, limit, increment) allows the increment to be changed.

--> ALL 1 | 2 | 3; [1, 2, 3] --> ALL 1:to(5); [1, 2, 3, 4, 5] --> ALL 1:to(5) | 5:to(1, -1); [1, 2, 3, 4, 5, 5, 4, 3, 2, 1]

As well as declaring and assigning values to variables, Wrapl provides a context for assigning a value to a temporary variable for the duration of a single expression. The expression WITH id1 <- expr1 DO expr2, assigns each value produced by expr1 to id1 and produces the values produced by expr2. Several variables can be used in the same WITH expression, in which case the expression behaves like several nested WITH expression.

--> ALL WITH i <- 1:to(10) DO i ^ 2 + i; [2, 6, 12, 20, 30, 42, 56, 72, 90, 110] --> ALL WITH i <- 1:to(5), j <- 1:to(5) DO i * j; [1, 2, 3, 4, 5, 2, 4, 6, 8, 10, 3, 6, 9, 12, 15, 4, 8, 12, 16, 20, 5, 10, 15, 20, 25] --> ALL WITH i <- 1:to(5) DO WITH j <- 1:to(5) DO i * j; [1, 2, 3, 4, 5, 2, 4, 6, 8, 10, 3, 6, 9, 12, 15, 4, 8, 12, 16, 20, 5, 10, 15, 20, 25]

The expression expr1 # expr2 interleaves the values produced by expr1 and expr2, i.e. it produces the first value from expr1 followed by the first value from expr2 then the second from expr1 and so on. Any number of expressions can be interleaved. The interleave expression fails when any of its subexpressions fail.

--> ALL 1:to(3) # 11:to(13) # 21:to(23); [1, 11, 21, 2, 12, 22, 3, 13, 23] --> ALL 1:to(10) # 11:to(14); [1, 11, 2, 12, 3, 13, 4, 14, 5]

The expression expr1 & expr2 produces the values produced by expr2 for each value produced by expr1. In effect, & is the "select right" operator. It can also function as a "logical and" operator, since it will only produce a value if both expr1 and expr2 produce a value.

Similarly, the expression expr1 \ expr2 produces the values produced by expr1 for each value produced by expr2, in effect the "select left" operator. Within expr2, the special variable $ refers to the value produced by expr1 Thus it can also function as a "logical and" operator, although it is mainly used to mean "such that".

--> 1 & 2; 2 --> 1 & 2 & BACK; failure --> 1 \ 2; 1 --> 1 & 2 \ 3; 2 --> 1:to(10) \ $ > 5; 6 --> ALL 1:to(3) & 10:to(12); [10, 11, 12, 10, 11, 12, 10, 11, 12] --> ALL 1:to(3) \ 10:to(12); [1, 1, 1, 2, 2, 2, 3, 3, 3] --> ALL 1:to(10) \ $ > 5; [6, 7, 8, 9, 10]

The more general function call K(expr1, ..., exprN), where K is an integer, produces the value of exprK provided all N values succeed, and 1 <= K <= N.

--> 2(1 + 2, "as" + "df", 79); "asdf" --> 4(1, 1, BACK, 1, 1, 1, 1); failure

Limiting and Skipping

The expression expr1 OF expr2 allows the number of values produced by expr2 to be limited; for each value N produced by expr1, the first N values produced by expr2 are returned.

--> ALL 5 OF 1:to(10); [1, 2, 3, 4, 5] --> ALL 1:to(4) OF 1:to(10); [1, 1, 2, 1, 2, 3, 1, 2, 3, 4]

On the other hand, the expression expr1 SKIP expr2 allows a number of the values produces by expr2 to be discarded, before producing the rest; for each value N produced by expr1, the values produced by expr2 are returned after discarding the first N values.

--> ALL 5 SKIP 1:to(10); [6, 7, 8, 9, 10] --> ALL 6:to(9) SKIP 1:to(10); [7, 8, 9, 10, 8, 9, 10, 9, 10, 10] --> ALL 10 OF 3 SKIP 1:to(20); [4, 5, 6, 7, 8, 9, 10, 11, 12, 13]

The expression @ expr1 produces all the values produced by expr1 ad infinitum. By itself, this is not much use, however combined with a limit expression, it becomes very powerful.

--> ALL @1; -- This won't terminate, until it runs out of memory ^CInterrupted --> ALL 10 OF @1; [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] --> ALL 10 OF @(1 | 2 | 3); [1, 2, 3, 1, 2, 3, 1, 2, 3, 1]

Navigate