Nix 式としてドキュメントを取得できるといいよねという話
岡本和樹
自己紹介
kakkun61.icon
岡本和樹
カンペキ
https://gyazo.com/7805afbae0007f2ae79bc9dd53293270
質問
Nix のつらいところって何ですか?
うん
そうだね!
型検査がないことだね!
本当は
「Nix 式としてドキュメントを取得できるといいよねという話」というタイトルですが、本当は「型検査があるといいよねという話」です
型システムの設計
どういう型システムにすればいいだろうか?
Nix 言語はかなり動的にオブジェクトのシェイプが決まる言語
code:flake.nix
{
inputs = {
nixpkgs.url = …;
foo.url = …;
};
outputs = { self, nixpkgs, foo }: { … };
};
既存の資源が利用できることは必須
部分的に型を付けていく
漸進的型付けシステム
それらを踏まえると JavaScript と TypeScript の関係に近いものになりそう
となると、漸進的型付けシステムになる
JS・TS と違うのは部分型付け関係がないこと
レコードに余分なキーがあることもある { foo, ... }: { … }
よって、PureScript にもある列多相を付けるとよさそう
妄想・基本型
構文を妄想してみる
まずは基本型
builtins.string
builtins.boolean
builtins.integer
builtins.float
builtins.path
builtins.any
妄想・複合型
次は複合型
set: { foo :: foo; }
list: [ foo ]
nullable: foo?
function: foo -> bar
union: foo | bar
merge: foo // bar
functor?
列多相?
妄想・複合型
Functor どうするよ
code:functor.nix
let add = { __functor = self: x: x + self.x; };
inc = add // { x = 1; };
in inc 1
A set that has a __functor attribute whose value is callable (i.e. is itself a function or a set with a __functor attribute whose value is callable) can be applied as if it were a function, with the set itself passed in first
議論求む
妄想・複合型
列多相どうするよ
PureScript ならこういうやつ
code:row.purs
forall (r :: Row Type). { first :: String, last :: String | r } -> String
showPerson { first: x, last: y } = y <> ", " <> x
議論求む
妄想・型注釈
ラムダ式
code:nix
x :: integer: x + 1
let 式
code:nix
let x :: integer = 1; in …
set リテラル
code:nix
{ a :: integer = 1; b :: string = ""; }
妄想・型定義
alias 式
code:nix
alias foo = builtins.integer; in …
alias foo = { bar :: builtins.integer; }; in …
alias foo = bar -> buzz; in …
set リテラル
code:nix
{
alias foo = builtins.integer;
};
妄想・ファイル
拡張子?
tix
d.tix
妄想・ファイル
型定義だけのファイル
code:nix
{ pkgs }:
let
company = import ./company.d.tix { inherit pkgs; };
in {
customer = {
name :: builtins.string;
address :: builtins.string;
company :: company;
};
};
妄想・ファイル
値定義に型が混じったファイル
code:nix
{ pkgs }:
let
common = import ./common.tix { inherit pkgs; };
in
alias
item = common.column | common.row
in {
inherit item;
pen :: item = {};
};
妄想・Nix OS モジュール
モジュールとの整合性をどうするか何も考えてなかった
Nix OS のモジュールシステムがあって、そこで型っぽいものを定義してたりする
実行時にシェイプの検査をしてくれる検査器とそれに渡す定義などをそう呼ぶ
とはいえ
Nix 言語を拡張して型検査器を実装していくのは大変だ
そこで
一旦あくまで人間向けに読めるドキュメントをコンピューターに扱える形でコメントを書きませんか?
理想的にはこんな感じ
code:nix repl
fooFunc = bar.buzz { … };
fooFunc ってどう使うか分かんないなあ
code:nix repl
doc fooFunc
fooFunc is a function that takes a set { hoge, huga } and returns a set { piyo, poyo } defined at boo.nix:42. Wakariyasui Setsumei.
fooFunc の引数と返り値のシェイプは set で boo.nix に定義されているのか、なるほど~
ってなるとある程度うれしい
書く側は
定義する側は
code:nix
fooFunc = …;
とするところを
code:nix
fooFunc = {
__functor = originalFooFunc;
doc = {
type = d.function;
returns = "{ piyo, poyo }";
definedAt = "boo.nix:42";
description = "Wakariyasui Setsumei";
};
};
いまいちポイント
returns definedAt が手書き
非対称的に引数は pkgs.lib.functionArgs で取得できる
おさそい
ええ感じの doc フィールドの形式の詰めと、doc 関数の実装をやって、はやらせよう!
💪💪💪💪💪💪