2.1 rank多相 -- rank polymorphism
全ての関数ではないが、rank多相を持つ関数は引数の型に対して以下のように振舞う。
- 両引数がatomの場合はそのまま関数適用をする
- 片方のみがatomである場合はatomデータを同じ形状の配列に持ち上げ、要素同士の関数適用を行う
- 形状が一致するprefixを持つ場合はそれ以降のshapeについてrank多相を再帰的に適用する
- それ以外の場合は形状不一致で実行時エラー
最も簡単でよく知られたスカラー値と配列の場合に話を単純化する1と上のルールは以下のように言い換えられる。
- 両引数がスカラーの場合はそのまま関数適用をする
- 両引数が配列でその形状が同じである場合は対応する要素同士の関数適用を行う(HaskellのFanctorみたいな感じ)
- 1引数が配列で他引数がスカラーである場合はスカラーデータを同じ形状の配列に持ち上げ、要素同士の関数適用を行う
- それ以外の場合は形状不一致で実行時エラー
スカラーから配列への持ち上げは𝕨と𝕩のどちらでも同じように行われる。
1+3 # atom-to-atom
4
1‿2‿3+5‿0‿2 # array-to-array
⟨ 6 2 5 ⟩
1+2‿3‿4 # atom-to-array
⟨ 3 4 5 ⟩
0‿1‿2+5 # array-to-atom
⟨ 5 6 7 ⟩
0‿1+2‿3‿4 # array-to-array
Error: Mapping: Expected equal shape prefix (⟨2⟩ ≡ ≢𝕨, ⟨3⟩ ≡ ≢𝕩)
at 0‿1 + 2‿3‿4
^
rank多相のdispatchが期待したものでない場合は、配列を「atom化」する(単位配列に入れる)enclose '<
' で対処することが一般的である2。
0=0‿2‿0‿1‿0‿2‿2 # この例では0と等しいかどうかの配列を作る
⟨ 1 0 1 0 1 0 0 ⟩
1=0‿2‿0‿1‿0‿2‿2 # 同様に1と等しいかどうかを調べる
⟨ 0 0 0 1 0 0 0 ⟩
0‿1=0‿2‿0‿1‿0‿2‿2 # 両方の処理をまとめて行いたいのだが
FIXME
0‿1=¨<0‿2‿0‿1‿0‿2‿2 # 片方をatom化したのでエラーが解決
FIXME
0‿1=<0‿2‿0‿1‿0‿2‿2 # rankの問題が解決したので明示的なmappingは不要
FIXME
∨´0‿1=<0‿2‿0‿1‿0‿2‿2 # 2つの結果をfoldして目的の結果を得た
⟨ 1 0 1 1 1 0 0 ⟩
FIXME
ちなみにこの目的を達成するなら別の関数を使った方が簡単になる。
0‿2‿0‿1‿0‿2‿2∊0‿1
⟨ 1 0 1 1 1 0 0 ⟩
1
APLの説明で必ず出てくるスカラーとベクターの加算は一般化されたルールの説明としては不十分。配列間での持ち上げに触れておかねば。 でなければbqncrateにある多次元に一般化された「行列」積が理解できないのではなかろうか。
2
実はこの方法は比較関数<
, ≤
, ⌊
などで期待した通りに動かない。
そのため、文字列の比較はやってみると意外に難しい。
ということでここで 設問🧑🎓:文字列𝕨, 𝕩のうち辞書的順序で小さい方を返す関数を定義せよ。