schemeで例外処理ってどうするんだろう?

例えば、与えられたリストをすべてかけた値が欲しいときなどに、0を発見したら処理を中断して0を返すようにしたい。こういうときに、例外が使えると便利そう。

ocamlだとこんな感じ

exception ZeroFound (*  例外の定義 *)

let product l =
  try 
    List.fold_left
      (fun it x -> match x with
	   0 -> raise ZeroFound
	 | _ -> x * it)
      1    l
  with
      ZeroFound -> 0;;

schemeでもできるか調べてみた。
srfi-34のguardを使うといいみたい。

(define (product l)
  (guard (con (else con))
    (fold (lambda (x it)
	    (if (zero? x) (raise 0) (* x it)))
	  1
	  l)))

(product '(1 2 0 3 2)) ;=> 0

raiseは一応どんなものでも渡せるみたいだけれど、普通はコンディションオブジェクトを渡すみたい。
自分で新しいコンディション*1を定義したい場合は、define-condition-typeを使う。

(define-condition-type <zero-found> <condition>
  #f)

(define (product l)
  (guard (con
          ((<zero-found> con) 0))
    (fold (lambda (x it)
	    (if (zero? x)
                (raise (condition (<zero-found>)))
		(* x it)))
	  1
	  l)))

*1:例外のことをコンディションっていうみたい