※全宇宙人にとって無価値な文章。

SENについて考えてたらブログの更新が異常に滞る。考えたこと書くだけならすぐだけど整合性を求め始めると時間と脳が溶ける。

◆参照のパターン

▼名前で参照

ファイルからの複数要素の参照ができるか。ディレクトリを指定することでディレクトリ配下の全ファイルを参照できるか。

つまり

sen
 └ types
   ├ Book.d.sen
   └ Details.d.sen

という状況における「sen/types/Book.d.sen」のファイル参照は良いとして、「sen/types」で配下のファイルを一括読み込みするようなことができるか。出来ない気がする。

そもそも名前ベースでの参照が出来ていない。

#Book : ?"https://example.com/sen/types/Book.d.sen"

この書き方だとd.senに定義された内容によらず内容をBookという名前にバインドしちゃってる。参照の文字列の後に識別子を書いたら個別の読み込みはできる。

#Book : ?"https://example.com/sen/types/Book.d.sen".Book

かたやJavaScriptだと以下のようにimportしている。

import defaultExport from "module-name";
import * as name from "module-name";
import { export1 } from "module-name";
import { export1 as alias1 } from "module-name";
import { default as alias } from "module-name";
import { export1, export2 } from "module-name";
import { export1, export2 as alias2, /* … */ } from "module-name";
import { "string name" as alias } from "module-name";
import defaultExport, { export1, /* … */ } from "module-name";
import defaultExport, * as name from "module-name";
import "module-name";

import – JavaScript | MDN (mozilla.org)

そうよね。名前で読めないと毎回フルパスを書かねばならなくてキツイかも?

#{ Book } : ?"https://example.com/sen/types/Book.d.sen"

これでいいんかな。今までの書き方と比較したら一貫性がないけど分かりやすい。d.sen内に定数やら型の定義が複数あるならカンマ区切りで読めるだろう。そしてディレクトリを対象にするんならつまり

#{ Book, Details } : ?"https://example.com/sen/types"

こういうことだろうか?分割代入みたい。でも

  • 名前空間が無いのでファイル名までの指定が必須
  • エイリアス必要

なので

#{ 
  Book : ?"Book.d.ts".Book, 
  Details : ?"Details.d.ts".Details,
 } : ?"https://example.com/sen/types"

こうかな。ハイライト効かないと見づらい。「#{}」でラベル代入用ブロックを記述できるんだろうな多分。ラベル代入用ブロックの中での参照は、そのフィールドの値として指定した参照先をルートにする。

ファイルまで指定した上でエイリアスをつけるなら

#{ BookA : ?Book } : ?"https://example.com/sen/types/Book.d.sen"

みたいなもんだろう。曖昧さがない。BookAの前に名称指定の「$」が付いてもいいし、付いてるなら順不同で良い。

#{ : ?Book $ BookA  } : ?"https://example.com/sen/types/Book.d.sen"

解釈可能。そしてすべての空白は除去してもいい。

◆関数

副作用のない関数をオブジェクトとして表現できるようにし、その簡易記法としてラムダを用意したい。でもそれも無駄に難しいかもと思った。例えば

(x) => x * 1.08

とか

(x, y) => x + y * 100

をオブジェクトとして表現するにしても、どうしたものやら?逆ポーランド記法みたいなLISPみたいなアレな話になるんだろうけど入れ子が凄そうだし、カリー化してもスコープがわけわからんことになる。だからオブジェクトに直すことをあまり考えず、関数は式として書きゃいいじゃんと思った。

だって式を記述できたとして、実処理は各処理系に委ねるしかない。計算結果とか精度について責任を取れない。と思うんだけども。でも数値の型をint8とかfloat32とか言い始めるとIEEEらへんで自ずと決まるものではあるな。

▼エスケープ

「`」で囲んで関数を表現するって話だったけど、文中に「`」が出てくるんならエスケープが必要。エスケープしたくないから「#“#」で囲む。

>hoge:{
  >fuga@func<number,number>:#`(#n) => ?n * 1.08`#
}

▼パイプ

「|>」でパイプライン。例えば組み込み関数のnumber.toStringを呼ぶときに

>hoge:{
  >fuga@func<number,number>:#`(#n) => number.toString(?n * 1.08)`#
}

じゃなくて

>hoge:{
  >fuga@func<number,string>:#`(#n) => ?n * 1.08 |> number.toString`#
}

みたいな書き方をできるようにしておく。「|>」の優先度は最低。優先度を変える必要があったらパーレンで囲む。

▼関数リスト

関数表現が貧弱すぎて、変数すら格納できない。変数を格納できないとちょっと昔のExcel関数みたいに辛い目に合う。だから最小限の機能は欲しい。

とにかく、そんな複雑なことは出来ないものであるという前提で考えたい。単純であれば並列処理も効く。

>hoge:{
  >fuga@func<number,string>:#`(#n) => [
    #x : ?n * 1.08;
    >> number.toString(?x);
  ]`#
}

「#」でラベルの定義はできる。定義したラベルを呼び出す前には参照の「?」が必要。

予約語を極力排したいし、空白をすべて取り除いても大丈夫なように「>>」をreturn句としている。RubyとかElixirみたいに最後の行の評価結果を戻り値として扱うこともできそうだけど、明示的じゃないのでしない。

関数内では直接的に外部参照をすることは出来ないだろう。そして、代入とreturn以外の行っていうか式は要らない気がする。Map以外のことをしないので。

▼if return

then returnというか。早期returnの書き方。「() >>」で開始としてみる。

nが10以上だったら100をreturnしたいときは以下の通り。

>hoge:{
  >fuga@func<number,number>:#`(#n) => [
    (?n > 10) >> 100;
    >> ?n;
  ]`#
}

▼if

Haskellのifってどうなってたっけと思って調べたらifは式で関数だった。それに倣うなら

>hoge:{
  >fuga@func<number,number>:#`(#n) => [
    >> if(?n > 10)(100)(?n);
  ]`#
}

こんなん?初見じゃわからんな。Haskellみたいにthenとかelseとか書かれてないと読みにくいかも。とはいえラベルへの再束縛みたいなのを許さないから機能としてはこんなんで問題なさそう。そしてifじゃのうて全てはswitch caseでいいんじゃねぇかな。ifみたいに関数にしづらいから構文になるけど。

「{}」を条件分岐関数実行ブロックとしよう。{}はシンタックスシュガーであり、関数の定義とその実行に書き換えられる。

>hoge:{
  >fuga@func<number,number>:#`(#n) => [
    >> {?n > 10 | then >> 100 | else >> ?n};
  ]`#
}

thenとelseはtrueとfalseに一致する。thenをtrue、elseをfalseと書いても動作する。

「?n > 10」を評価した結果が「|」直後の式に一致した場合returnの内容を返す。単項でない場合はパーレンで囲まなければならない。

他の言語に書き換えられるかどうかだけ考えればいいんだけども、クロージャとか考えねばならん気がするな。

さっきみたいに「|」直後に定数がきた場合は、その定数を取った比較関数を生成して条件分岐の対象を適用し、真偽を評価する。「|」直後に関数がきた場合は対象を適用して真偽を評価する。

>hoge:{
  >fuga@func<number,number>:#`(#n) => [
    >> {?n | (> 10) >> 100 | (>= 0) >> ?n | _ >> 0};
  ]`#
}

関数「>」に10を適用したら、引数が10より大きいかどうかを判定する関数が戻る。関数「>=」も同じノリ。関数「_」(破棄)は何が渡ってもtrueが返る。

正しく書くなら「>」は関数なんで「>(10)」というふうに10を渡さねばならんが、これもシンタックスシュガーなんだろう。解釈するときに「>」を適切な関数に読み替えればいい。

C#みたいなパターンマッチングがしたいというだけ。

▼for文

要らんのでは?あくまでデータ記述なんですから、そんな複雑な事できないよ。mapとかfilterとかのリスト操作関数はあろうけども。

▼マルチ引数

複数の引数を渡す際はパーレンで囲んで記述。

>hoge:{
  >fuga@func<(number, number), number>: #`(#tax, #n) => ?n * ?tax`#
}

上記は以下の簡易的な記法。

>hoge:{
  >fuga@func<number, func<number, number>>: 
    #`(#tax) => (#n) => ?n * ?tax`#
}

▼引数適用

senの記法として関数に対し変数を入れたし。例えば

"https://example.com/tax.sen".tax

に「1.08」が格納されているものとする。

とても単純に考えるんならもう連結してしまえばいい。

>hoge:{
  >fuga@func<number,number>:
    #`(#n) => ?n * `# ?"https://example.com/tax.sen".tax
}

けど、関数の記述に侵食しちゃってるようで嫌です。インジェクションもありそう。とりあえずは引数を書いてあげて適用してあげよう。

>hoge:{
  >fuga@func<number, number>:
    #`(#tax, #n) => ?n * ?tax`#(?"https://example.com/tax.sen".tax)
}

関数記述後にパーレンで引数を食わす。読みにくいが、こういうことだろう。変換後こうなることを見越してシンタックスシュガーを考える。

>hoge:{
  >fuga@func<number, number>:
    #`(#n) => 
     {#tax: ?"https://example.com/tax.sen".tax}
      >> ?n * ?tax
    `#;
}

こうとか。

>hoge:{
  >fuga@func<number, number>:
    #`(#n) => 
      {#tax@number: ?"https://example.com/tax.sen".tax};
      [>> ?n * ?tax;];
    `#
}

こうだろう。「=>」直後の「{}」内側でラベルを指定し、後に関数を記述する。実質的に関数内では外部参照できないが、記法的に外部参照を許しているかのように書ける。

とても色々言えるけどもう疲れたのでまた来年考える。

◆算出

算出プロパティ。インスタンスの各要素と定数から算出されるプロパティ。「&」で開始とする。

*Book:{
  >price@number
  &taxed: #`(#this) => 
    {#tax: ?"https://example.com/tax.sen".tax};
    >> ?this.price * ?tax;
    `#
}

これでいいんじゃないの。thisという引数は別にcontextとかって名前で受けてもいいだろうし。型にラベルを書いたら以下。

*Book:{
  #t@number: ?"https://example.com/tax.sen".tax
  >price@number
  &taxed: #`(#this) => 
    {#tax: ?t};
    >> ?this.price * ?tax;
    `#
}

ラベル名重複は許されぬ。というのと、関数の静的解析のためにラベルに型の指定は必要かもな。

使い道?表計算したりフォームを表現したりすんだよカス。

◆数値

JSONみたいなnumberという抽象的な数値と、i32とかu64とかの具体的な数値がありそう。

JSONの数値は書けさえすればなんでもありだけど、デシリアライズするときに必要なメモリ領域の判断がつかんので効率が出せない。符号なし8bitに収まる数値しか使わんのに64bitのfloatにせざるを得ない。

組み込み型としてnumberと、intやらfloatやらuintは分けて考えなければならなそう。なにもなく数値を書いたらnumberだが、型の指定で具体的な数値表現も使えればいい。numberの精度は処理系に委ねられる。

◆めも

  • 実装ランク。低ランクだとデータ記述のみ。高ランク実装だと関数まで対応とか。
  • バイナリデータのバイト解析情報を記述できるか考えてみたい。算出があればなんとかなるような。ならないような。
  • 日付表現とか関数表現はSENから取り出して成り立つものなので結合を切っておきたい。