3.9. kink/FUN

The companion mod for fun vals.

3.9.1. type fun

A fun is a function value. See “Language specification” → “Kink Stack Machine (KSM)” chapter for function values.

Fun.ensure($cleanup)

Fun.ensure ensures $cleanup thunk is invoked when the invocation of Fun thunk terminates.

Fun.ensure invokes Fun with no args.

If the invocation of Fun terminates without raising an exception, escaping by CONTROL.escape, or calling CORE.shift to an outer continuation tag, $cleanup is invoked in a execution stack different from the current execution stack. If the execution stack terminates without raising an exception, Fun.ensure returns the result of the invocation of Fun. If the execution stack terminates raising an exception, Fun.ensure reraises the exception.

If the invocation of Fun terminates raising an exception, or escaping by CONTROL.escape, $cleanup is called by CORE.reraise or CONTROL.escape in a execution stack different from the current execution stack.

Example:

:divide_10_by <- {(:Divisor)
  :do_division <- {
    { 10 // Divisor }.ensure{
      stdout.print_line('exit from $do_division')
    }
  }
  { do_division }.ensure{
    stdout.print_line('exit from $divide_10_by')
  }
}

stdout.print_line(divide_10_by(2).repr)
# Output:
#   exit from $do_division
#   exit from $divide_10_by
#   5

{ divide_10_by(0) }.try(
  { raise('must not reach here') }
  {(:Msg :Traces)
    stdout.print_line('exception: {}'.format(Msg))
  }
)
# Output:
#   exit from $do_division
#   exit from $divide_10_by
#   exception: Num.op_intdiv: zero division: 10 is divided by 0

Fun.try($on_returned $on_raised)

Fun.try traps an exception raised by an invocation of Fun.

Fun.try invokes Fun with no args.

If the invocation of Fun terminates without raising an exception, Fun.try tail-calls $on_returned with the result of the invocation of Fun.

If the invocation of Fun terminates raising an exception, Fun.try tail-calls $on_raised with the message str and a vec of the traces.

Example:

:TRACE.require_from('kink/')
:attempt_divide_10_by <- {(:Divisor)
  { 10 // Divisor }.try(
    {(:Result)
      stdout.print_line('result: {}'.format(Result))
    }
    {(:Msg :Traces)
      TRACE.format_traces(Msg Traces).each{(:Line)
        stdout.print_line(Line)
      }
    }
  )
}

attempt_divide_10_by(2)
# Output:
#   result: 5

attempt_divide_10_by(0)
# Output:
#   exception traces: from oldest to newest
#   [launch]
#   [builtin:kink-mods/kink/_launch/LAUNCH_KINK.kn L194 C5 try] }.-->try(
#   [reset]
#   [builtin:kink-mods/kink/_launch/LAUNCH_KINK.kn L193 C5 start] -->start(Non_opts)
#   [builtin:kink-mods/kink/_launch/LAUNCH_KINK.kn L129 C19 if_else] Non_opts.empty?.-->if_else(
#   [builtin:kink-mods/kink/_launch/LAUNCH_KINK.kn L137 C7 _run_script] -->_run_script($script_fun Script_args)
#   [builtin:kink-mods/kink/_launch/LAUNCH_KINK.kn L123 C3 script_fun] -->script_fun(Env)
#   [(stdin) L19 C1 attempt_divide_10_by] -->attempt_divide_10_by(0)
#   [(stdin) L3 C21 try] { 10 // Divisor }.-->try(
#   [reset]
#   [(stdin) L3 C8 op_intdiv] { 10 -->// Divisor }.try(
#   exception message: Num.op_intdiv: zero division: 10 is divided by 0

Fun.run_in_new_stack($on_returned $on_raised)

Fun.run_in_new_stack invokes Fun in a new execution stack.

Fun.run_in_new_stack makes a new execution stack, and invokes Fun with no args.

If the execution stack terminates without raising an exception, Fun.run_in_new_stack tail-calls $on_returned with the result of the execution stack.

If the execution stack terminates raising an exception, Fun.run_in_new_stack tail-calls $on_raised with the message str and a vec of the traces.

Example:

:TRACE.require_from('kink/')
:divide_10_in_new_stack <- {(:Divisor)
  { 10 // Divisor }.run_in_new_stack(
    {(:Result)
      stdout.print_line('result: {}'.format(Result))
    }
    {(:Msg :Traces)
      TRACE.format_traces(Msg Traces).each{(:Line)
        stdout.print_line(Line)
      }
    }
  )
}

divide_10_in_new_stack(2)
# Output:
#   result: 5

divide_10_in_new_stack(0)
# Output:
#   exception traces: from oldest to newest
#   [(stdin) L3 C8 op_intdiv] { 10 -->// Divisor }.run_in_new_stack(
#   exception message: Num.op_intdiv: zero division: 10 is divided by 0

Fun.while_true($body)

Fun.while_true invokes $body thunk repeatedly while Fun thunk returns true.

Fun.while_true first calls Fun with no args. If Fun returns true, Fun.while_true calls $body with no args. It repeats until Fun returns false.

Fun.while_true returns nada.

Fun must return true or false.

Example:

:Strs <- ['foo' 'bar' 'baz']
{ Strs.nonempty? }.while_true{
  :S = Strs.pop_front
  stdout.print_line(S)
}
# Output:
#   foo
#   bar
#   baz

3.9.2. FUN.fun?(Val)

FUN.fun? returns whether the Val is a fun.