##lookin ..Shapes
/** Define some function that uses the error mechanism to report bad input.
 **
 ** (To make it simple we avoid a helper function, but this will clearly
 ** lead to a performance loss since the type and range of the argument will
 ** be checked over and over again.)
 **
 ** By not using cond to check for the error conditions, it becomes clearer
 ** what is error-checking and what is normal evaluation.
 **/
factorial: \ i →
  {
    ![if [typeof i] ≠ Data..Type..§Integer
         [error 'type_mismatch VARNAME Data..Type..§Integer.name (indexof i) i]]
    ![if i < '0
         [error 'out_of_range VARNAME `The factorial is not defined for negative values.´ (indexof i)]]
    [if i = '0
        '1
        i * [factorial i-'1]]
  }
/** Define a new function, which captures and handles one of the errors that factorial may report.
 ** The implementation follows a pattern, so it can be learned even if it cannot be abstracted away
 ** in a function.
 **/
ext_factorial: \ i →
  (escape_continuation return
    (escape_continuation error
      (escape_continue return
        [factorial i]))
    >>
    \ ball →
      [Control..cond
        [Data..cons ball.kind = 'out_of_range
              '~1]
        [Data..cons ball.kind = 'dtmin
              [error 'misc VARNAME `Why on earth did we get a dtmin error here?!´]]
        [Data..cons true
              (escape_continue error ball)]])
/** Try the new function!
 **/
IO..•stdout << [ext_factorial '10] << "{n}
IO..•stdout << [ext_factorial '~10] << "{n}
/** But don't do this, since the type mismatch error will be re-thrown by ext_factorial:
 **/
|**IO..•stdout << [ext_factorial 10] << "{n}
 |