7.3 特殊名を使用するブロック

特殊名による関数参照で作られる予期せぬ関数定義ブロック

以下は条件分岐をする関数を定義する例だがうまく動いていない。なぜだろうか。

    Solve ← {part 𝕊 d :
      {1=part ? d ;
       2=part ? ∞ ;
                d 𝕊 d    # 再帰呼び出し
      }
    }
    3 Solve 1       # 実行すると
⟨function block⟩    # 評価されていない

問題は条件分岐に使われているブロックの形式にある。

    part‿d ← 0‿1
⟨ 0 1 ⟩
    {1=part ? d ; 2=part ? ∞ ; d 𝕊 d}    # 複文のように見えるが
(function block)

条件分岐のブロックの中では𝕊が使われているが、これは最内ブロックを指す特殊名であり、その結果 このブロックは条件分岐の複文ブロックではなく、ヘッダーなし関数定義ブロックと見做される。 関数の最後の式が関数定義なのでSolveは関数を返す関数になってしまっている。 これを複文ブロックとするためには特殊名の使用をやめなければならない。従ってSolve𝕊以外の名前を付けるか、Solveそのものを指定するように書き換えなければならない。

   Solve ← {part Fn d : {1=part ? d ; 2=part ? ∞ ; d Fn d}}  # 内部名Fnを使用
(function block)
   0 Solve 1
1
   Solve ↩ {part 𝕊 d : {1=part ? d ; 2=part ? ∞ ; d Solve d}}  # 外部名を使用
(function block)
   0 Solve 1
1

条件分岐を{}で囲むことをやめてもよさそうに思えるが、そうすると今度は識別子のスコープの問題が生じるため実際的ではないことが多い。

   Solve ← {part 𝕊 d :
     1=part ? d ;
     2=part ? ∞ ;
              d 𝕊 d
   }
Error: Undefined identifiers
    2=part ? ∞;
      ^^^^

特殊名による引数参照で作られる予期せぬ関数定義ブロック

上の問題は関数の参照によって予期せぬ関数定義ブロックが作られた例だったが、 𝕩𝕨を使った引数の参照でも同じことに起きる。

    F ← {𝕨 𝕊 𝕩 :
      {•Show 𝕨×𝕩 ⋄ 𝕨‿𝕩 (-¬) ↩}    # 何かしら複文のブロックが必要だったとする
    }
(function block)
    2 F 2               # 実行すると
(function block)        # 評価されていない

先と同じようにブロックの中で特殊名𝕩, 𝕨を使ったため関数定義になってしまったのが原因なので、同じ対策が必要である。

    F ← {w 𝕊 x :
      {•Show w×x ⋄ w‿x (-¬) ↩}      # 参照したい引数に固有の識別子を与える
    }
    F ← {𝕨 𝕊 𝕩 :
      𝕨{•Show 𝕨×𝕩 ⋄ 𝕨‿𝕩 (-¬) ↩}𝕩    # 必要な引数を与える
    }

自分のAoCのリポジトリ中に以下のメモを見つけたので貼っておきます。

;はブロックの途中でreturnするものではなく、そこでブロックが終っている。 つまり;の前後で違うブロックが定義されていると思った方がよい。

     F ← {
       temp ← 0
       𝕩 = 1 ? temp+1;
       temp ↩ 0        # tempに再代入したのだが
       temp+2
     }
Error: Undefined identifier
at       temp ↩ 0
         ^^^^
     F ← {
       temp ← 0
       𝕩 = 1 ? temp+1;
       temp ← 0        # ということで、ここで必要なのは ↩ ではない!
       temp+2
     }
(function block)