##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}
|