Skip to content

v0.1.z での構文の変更案

Takashi Suwa edited this page Jun 19, 2021 · 5 revisions

型註釈を括弧で追記できるようにする

let succ (x : int) = x + 1 in succ 42

トップレヴェルでの値の束縛を val にする

トップレヴェルでの値の束縛は(let ではなく)val によって行なう.局所的な束縛は引き続き letrec は独立したキーワードとする.let-inlineval inline/let inline で記述する.inlineblockmath は新たにキーワードとする.math は(引き続き)型名としても使う.

val add x y =
  x + y

val add-partial x =
  let f y = x + y in f

val rec power n =
  if n <= 0 then 1 else n * power (n - 1)

val inline ctx \display-power n =
  Inline.read ctx (Inline.embed-string (String.arabic (power n)))

val is-even-nat (n : int) : bool =
  let rec odd n =
    if n == 0 then false else even (n - 1)

  and even n =
    if n == 0 then true else odd (n - 1)
  in
  if n < 0 then false else even n

リストとレコードの内容をコンマ区切りにする

区切り記号を ; ではなく , にする.また,末尾の , も許容する.

val nums = [3, 1, 4, 1, 5, 9, 2]

val people =
  [
    (| name = {Alice}, age = 25 |),
    (| name = {Bob}, age = 32 |),
  ]

match 式の終端に end をつける

いわゆるぶら下がりの防止のため.

val is-empty xs =
  match xs with
  | []     -> true
  | _ :: _ -> false
  end

型パラメータの後置

type tree 'a =
  | Leaf
  | Node of list (tree 'a)

全称量化の明示

val rec tree-size 'a (tr : tree 'a) =
  match tree with
  | Leaf      -> 0
  | Node(trs) -> trs |> List.fold-left (fun n tr -> n + tree-size tr) 0
  end

module List : sig
  val find-map 'a 'b : ('a -> option 'b) -> list 'a -> option 'b
end

val get-name 'a ('b :: (| name : 'a |)) : 'b -> 'a

direct の廃止

従来はモジュールの表現力が限られていたこともあって “グローバルな名前空間でも束縛する,val の拡張版” として direct を用意していたが,これはモジュールシステムのF-ing modules化により不用意な複雑化を避け廃止したい.一方でコマンドをグローバルな名前空間へと取り出すのは使う側の責務とする.

古いグラフィックス用の構文の廃止

cyclecontrols--..<[]> といったトークンとそれによる構文を廃止する.もともとはTikZ風にパスを記述できるようにするためのものだったが,パス用プリミティヴやグラフィックス用のモジュールで事足りるようになった.

プリミティヴをモジュール Prim にまとめる

プリミティヴは直接アクセスできないようにし,ひとつのモジュール Prim にまとめる.名前空間を節約するほか,更新を後方互換にしやすくする意図がある.

さらに言えば,この Prim のメンバ自体も通常の用法ではできるだけ直接使用せず,satysfi-base などを介して使うことを推奨するようにする.

.satyh などは1ファイル全体で1モジュール化

従来はトップレヴェルの名前空間で直接束縛できたが,衝突防止のためこれをできないようにする.したがってライブラリをなす各ファイルは以下のような構造に限定される:

〈require など他のファイルへの参照〉

module 〈モジュール名.原則としてファイル名と同じ〉 : sig
  〈API〉
end = struct
  〈実装〉
end

また,これはデファクトスタンダードのパッケージマネージャであるSatyrographosとの責務の分担を議論する必要がありそうだが,今のSatyrographosが扱っているopamパッケージの単位で “1パッケージにつき丁度1モジュールがexportされる” という制約を設ける.例えば satysfi-base なら Base というモジュールのみがグローバルに読み込まれ,個々の機能のモジュールは Base.String とか Base.RegExp といった入れ子のモジュールになる要領.

この仕組みを先んじて設計・実装したSesterlでなかなか奏功している様相のため,SATySFiでも同様の仕組みにするとよいかもしれないという検討.

requireの変更

従来の @require: で相対パスを指定するのではなく,モジュール名で指定して同ライブラリ中の別モジュールまたは外部パッケージを読み込む:

require Base

ただし,“require の記述のみからマシンにインストールされたパッケージで該当のものを見に行く” という従来の @require: と同様の振舞いをさせるか否かはやや議論の餘地がありそう.文書という長期の保守が重要となりうる用途であることを鑑みるとビルドの再現性が高いことが望ましく,ライブラリのヴァージョンなどの情報が別途メタ的に記述される仕組みがある方が無難ではないか.

  • ライブラリの場合:
    • Satyrographosの Satyristes ファイルなどに与えればよさそう.
    • ただし,SATySFi本体も何らかの方法でそのメタ情報に依存して処理をする必要があるのが少し厄介.
      • メタ情報に明示されていないがマシンにインストールされているパッケージを見に行くような挙動をすべきでないため.
  • 文書ファイルの場合:
    • メタ情報は勿論必要.
    • ちょっとしたレポートなどの執筆にも使われるので,軽量に書けることが望ましい.
      • 文書本体の上部にメタ情報を書ける仕組み(OCamlの [@@foo …] とかRustでいう #[foo(…)] のようなものでよい)があるべきかも.
      • ヴァージョン情報などが省略されていても,既に該当の名前のライブラリがマシンにインストールされていれば警告を出しつつ処理を継続する,というくらいでよいかも.

ちなみに,無くても言語機能上の支障はないが,以下のように補助的に名前変更やopenを簡便に行なう機能があってもよさそう:

require Base as B
require open Base
Clone this wiki locally