名前空間

名前空間はフィールド名によるデータアクセスを可能にするので構造体のようにも使える。 特に名前空間の中の関数は環境内の変数に対する代入をサポートしているので状態をもつオブジェクトとして使うことが可能である。

mutabilityとブロック

名前空間を使ってmutableなオブジェクトを作ったとしよう。 mutableなフィールドデータを参照するメソッドはクロージャすなわち定義ブロックでなければならない。 ブロック内での識別子アクセスは正しくenviroment chainをたどるが、そうでない関数はデータの更新を追いかけないからである。

    d ← {
      table ← [0‿1,"A"‿"B"]
      Set ⇐ {table 𝕩⌾(𝕨⊸⊑1⊸⊏) ↩}
      GetB ⇐ {((⊏table)⊐𝕩)⊏1⊏table}    # closure版
      GetT ⇐ (⊏table)⊸⊐⊸⊏⟜(1⊏table)    # train版
    }
    •Show [⟨"GetB",d.GetB⌾⋈1⟩,⟨"GetT",d.GetT⌾⋈1⟩]
┌─
╵ "GetB" "B"
  "GetT" "B"
             ┘
    1 d.Set "b"
    •Show [⟨"GetB",d.GetB⌾⋈1⟩,⟨"GetT",d.GetT⌾⋈1⟩]
┌─
╵ "GetB" "b"
  "GetT" "B"        # 更新されていない
             ┘

Try it online⌨️

使用例

稼働第1バージョン

環境変数群をenv経由で読み取り、いつでもどの環境変数でもアクセスできる名前空間envを作ろう。

外部プログラムはsystem value•SHを使って呼び出せる。

    •SH<"cal"      # 文字列のリストを要求する
⟨ 0 "     July 2023
Su Mo Tu We Th Fr Sa
                   1
 2  3  4  5  6  7  8
 9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31
" ⟨⟩ ⟩
    1⊑•SH<"env"    # 大事な1要素の標準出力の結果のみ必要
"COLORTERM=truecolor
LC_CTYPE=UTF-8
TERM=alacritty
EDITOR=hx
CXX=clang++
CC=clang
LD_DYLD_PATH=/usr/lib/dyld
NIX_STORE=/nix/store
...

この出力をkey-value形式のrank=2の配列に変形すると以下のようになる。

    vars ← >{(⊑'='⊸(⊐˜))⊸(↑⋈(1⊸↓↓))𝕩}¨1↓((¬×(1++`))(@+10)⊸=)⊸⊔1⊑•SH<"env"
┌─
╵ "COLORTERM"           "truecolor"
  "COMMAND_MODE"        "unix2003"
  "LC_CTYPE"            "UTF-8"
  "LaunchInstanceID"    "D27E85ED-4FA3-4DAD-8FAA-FCD3D8F35D96"
...
   {1⊑⊏((𝕩⊸≡)¨((<⊑)˘))⊸/vars}"LC_CTYPE"
"UTF-8"

⟨"LC_CTYPE","UTF-8"⟩とマッチするセルを探すなら

    ⟨"LC_CTYPE","UTF-8"⟩⊸≡⊸/m

となり、このセルから値を取り出すために、

     1⊑⊏⟨"LC_CTYPE","UTF-8"⟩⊸≡⊸/m

となる。 検索キーを𝕩とし関数名をVarとすると以下のようになる。

    vars ← >{(⊑'='⊸(⊐˜))⊸(↑⋈(1⊸↓↓))𝕩}¨1↓((¬×(1++`))(@+10)⊸=)⊸⊔1⊑•SH<"env"
    Var ⇐ {1⊑⊏(𝕩⊸≡¨(<∘⊑˘))⊸/vars}

これらを名前空間envにバインドすると以下のようになる。

    env ← {
        vars ← >{(⊑'='⊸(⊐˜))⊸(↑⋈(1⊸↓↓))𝕩}¨1↓((¬×(1++`))(@+10)⊸=)⊸⊔1⊑•SH<"env"
        Var ⇐ {1⊑⊏(𝕩⊸≡¨(<∘⊑˘))⊸/vars}
    }
    env.Var "COLORTERM"
"truecolor"

エラー対応

値を持たない環境変数を与えるとenv.Varがエラーを起こす。

そこでCatch ''を使って不適切な添字による要素のアクセスでのエラーを捉えることにしよう。

    env ← {
        vars ← >{(⊑'='⊸(⊐˜))⊸(↑⋈(1⊸↓↓))𝕩}¨1↓((¬×(1++`))(@+10)⊸=)⊸⊔1⊑•SH<"env"
        Var ⇐ {1⊸⊑∘⊏⎉"" (𝕩⊸≡¨(<∘⊑˘))⊸/vars}
    }
    env.Var "COLORTER"
""

さらに見つからなかった場合の既定値を与えられるようにする。 dyadic applicationによって規定値は与えてもよいし, monadic applicationとして与えなくてもよい。

    env ← {
        vars ← >{(⊑'='⊸(⊐˜))⊸(↑⋈(1⊸↓↓))𝕩}¨1↓((¬×(1++`))(@+10)⊸=)⊸⊔1⊑•SH<"env"
        Var ⇐ {𝕊 𝕩 : ""𝕊𝕩 ; 𝕨 𝕊 𝕩 : 1⊸⊑∘⊏⎉𝕨 (𝕩⊸≡¨(<∘⊑˘))⊸/vars}
    }
    env.Var "COLORTER"
""
    "FullColor" env.Var "COLORTER"
"FullColoro"

並列検索

この方法は配列varの変形と検索を検索キーの個数回実行しており関数プログラミング的ではあるが処理を並列に行う余地がない。 実は検索系の関数は複数の検索キーを渡す事ができるので、そのようなグリフを使うだけで並列化される可能性が高い。 そこで/を使ったフィルタリングで目的要素を見つける関数型プログラミングから、検索キーの添字を全部返すを使った配列志向のプログラムに変更しよう。

TBC