これは完全に行うことができ、多くの場合、事前/事後条件を取得する機能は、loop/recur特殊形式を使用しないことで失われる速度に見合う価値があります。
recur特殊形式は、実際には関数呼び出しではないため、yaに対しては実行されません。すべてのコードの実行後に事前条件と事後条件で境界チェックを行う独自のラッパー関数を作成するか、組み込みtrampoline
関数を使用して少しの労力を節約し、反復ごとに条件をチェックすることができます(あなたはあれが欲しい)
スタックを吹き飛ばすことなく、これを再帰関数に変えることができます。
(defn countup [x]
{:pre [(>= x 0)]
:post [(or (ifn? %) (>= % 0))]}
(if (< x 1000000)
#(countup (inc x))
x))
(trampoline (countup 0))
1000000
これにより、post条件が変更され、中間のケース(次に実行する関数が返される)が無視され、最終結果のみが検証されます。
トランポリンの背後にある考え方は、関数の各反復が直接呼び出すのではなく、次の関数への呼び出しを返すようにすることで、スタックを壊さないようにすることです。このようにして、1つの2つのスタックフレームが使用されます(1つはトランポリン用、もう1つは現在のステップ用)