1: doctype "calculator-lambda-0_2_1.g.etl";
     2: include "prelude-logic.c.etl";
     3: 
     4: /// The construct lazy value from the lambda abstraction
     5: ///
     6: /// @param f the function
     7: /// @return the function that remembers the result invocation of 
     8: ///         the function without arguments 
     9: let q'&' = {? var f;
    10:     assert f != null;
    11:     var value;
    12:     {?;
    13:         if(f != null) {
    14:             value = f();
    15:             f = null;
    16:         };
    17:         value;
    18:     };
    19: };
    20: /// The implementation of NotEqualDeref operator
    21: to q'!*='(x, y) =>  * x != * y;
    22: /// The implementation of EqualDeref operator
    23: to q'=*='(x, y) =>  * x == * y;
    24: 
    25: /// The maximum value (works for comparable objects)
    26: to max(x, y) => x < y ? y : x;
    27: /// The minimum value (works for comparable objects)
    28: to min(x, y) => x < y ? x : y;
    29: 
    30: /// Ensure that the number in the range of integer values.
    31: /// @param x the number to check
    32: /// @return itself (to allows variable arguments) 
    33: to assertIntRange(x) => {
    34:     assert MIN_INTEGER <= x && x <= MAX_INTEGER : "The value is "+x;
    35:     assertIntRange;
    36: };
    37: 
    38: /// Ensure that the number is the integer (there is no fractional pat).
    39: /// @param x the number to check 
    40: /// @return itself (to allows variable arguments) 
    41: to assertInt(x) => {
    42:     assertIntRange(x);
    43:     assert x % 1 == 0 : "The value is "+x;
    44:     assertInt;
    45: };
    46: 
    47: /// Ensure that the number is the non-negative integer.
    48: /// @param x the number to check 
    49: /// @return itself (to allows variable arguments) 
    50: to assertNonNegativeInt(x) => {
    51:     assertInt(x);
    52:     assert x >= 0 : "The value is "+x;
    53:     assertNonNegativeInt;
    54: };
    55: 
    56: /// The factorial value
    57: ///
    58: /// @param n the non-negative integer value
    59: /// @return the factorial result
    60: let factorial = {?n;
    61:     assertNonNegativeInt(n);
    62:     to fac(x) => x match { 0 => 1; else x * fac(x-1); };
    63:     fac(n);
    64: };
    65: 
    66: letrec {
    67:     /// Odd number check
    68:     /// 
    69:     /// @param x a non-negative integer number
    70:     /// @return true for odd numbers, false for even ones
    71:     is_odd = {?x; assertNonNegativeInt(x); x != 0 && !is_even(x-1);};
    72:     /// Even number check
    73:     /// 
    74:     /// @param x a non-negative integer number
    75:     /// @return false for odd numbers, true for even ones
    76:     to is_even(x) => {assertNonNegativeInt(x); x == 0 || is_odd(x-1);};
    77: };
    78: 
    79: /// Repeats execution of the one argument function from low to high
    80: /// adding +1 on each step until the resulting value will be higher then
    81: /// high. The example below will print numbers 1.5, 2.5, 3.5, and 4.5.
    82: /// {@example
    83: ///   1.5 #upto 5 {?i;
    84: ///      print i;
    85: ///   }; }
    86: /// 
    87: /// If the high value is greater then the low value, the cycle is never executed.
    88: ///
    89: /// @param low the start value for the loop (must be in integer range)
    90: /// @param high the limit value for the loop (must be in integer range)
    91: /// @param f the closure to use for the loop. 
    92: ///          If it returns false, the cycle is aborted, 
    93: ///          all other values are ignored.
    94: /// @return null value
    95: to upto(var low, high, f) => {
    96:     assertIntRange(low, high);
    97:     while(low<high && f(low) != false) {
    98:         low = low + 1;
    99:     };
   100: };
   101: 
   102: /// Repeats execution of the one argument function from start to limit
   103: /// adding step on each step until the resulting value will be higher or lower then
   104: /// limit (the direction depends on step's sign). 
   105: /// {@example
   106: ///   for(5,1,-0.125) {?i;
   107: ///      print i;
   108: ///   }; }
   109: /// 
   110: /// If the high value is greater then the low value, the cycle is never executed.
   111: ///
   112: /// @param start the start value for the loop (start/step must be in integer range)
   113: /// @param limit the limit value for the loop (limit/step must be in integer range)
   114: /// @param step the loop step (must ot be 0)
   115: /// @param f the closure to use for the loop. 
   116: ///          If it returns false, the cycle is aborted, 
   117: ///          all other values are ignored.
   118: /// @return null value
   119: to for(var start, limit, step, f) => {
   120:     assert step != 0;
   121:     assertIntRange(start/step, start/step);
   122:     while((step > 0 ? start<limit : start>limit) && f(start) != false) {
   123:         start = start + step;
   124:     };
   125: };
   126: 
   127: /// Convert Java number to integer
   128: @JavaMethod("java.lang.Number", "intValue")
   129: let toInt;
   130: 
   131: /// Convert a value to string
   132: @JavaMethod("java.lang.Object", "toString")
   133: let str;
   134: 
   135: @JavaMethod("java.lang.Math", "abs", "double")
   136: let abs;
   137: 
   138: @JavaMethod("java.lang.Math", "sin", "double")
   139: let sin;
   140: 
   141: @JavaMethod("java.lang.Math", "cos", "double")
   142: let cos;
   143: 
   144: /// Sign of the number
   145: ///
   146: /// @param x the floating point number to check
   147: /// @return -1, 0, or 1 depending on th sing of the number
   148: let sign = \x => select { x < 0 => -1; x > 0 => 1; else 0; };