Decodal/doc/manual/souce/language/functions.md
2026-06-16 01:27:54 +09:00

2.5 KiB

関数

関数は構造を受け取り、構造を返す式として扱う。

構文

(part: {
    greet = String;
    target = String;
}) =>
    "${part.greet}! ${part.target}"

関数呼び出しは通常の呼び出し構文で行う。

mk_hw({
    greet = "Hello";
    target = "World";
})

複数引数の構文は候補として以下を想定する。

(
    input_a: {
        hoge = Int & >= 0;
    },
    input_b: {
        fuga = 20;
    }
) =>
{
    # ...
}

関数の意味

関数は値として扱える。 ただし、最終データとして関数値を出力できるかどうかは別途定める。 設定ファイルを materialize する段階では、未適用の関数値は出力不能な値として扱うのが自然である。

評価方針

関数は以下の方針を基本とする。

  • 関数は純粋である。
  • 関数はレキシカルスコープを持つ。
  • 関数は定義時の環境を参照として保持する。
  • 引数は必要になるまで評価しない。
  • フィールドに束縛された関数呼び出し結果は、そのフィールド評価結果として memoize される。
  • 任意の関数呼び出しそのものをグローバルに memoize することは必須ではない。

関数値の内部モデル例:

Function {
  params: Vec<Param>
  body: ExprId
  env: EnvRef
}

関数と重さ

関数の文法・パーサー自体は大きくない。 実装上の重さは、主に評価モデルと意味論から発生する。

注意点:

  • クロージャが環境を掴む。
  • 引数を lazy にするか strict にするかを決める必要がある。
  • 関数呼び出し結果をどこまで memoize するかを決める必要がある。
  • 再帰関数を許可するかを決める必要がある。
  • 関数値同士の & をどう扱うかを決める必要がある。
  • 関数値を object に入れたとき、materialize 可能かを決める必要がある。
  • import 循環と関数適用が絡んだときの cycle detection が必要になる。

軽量に保つため、初期仕様では以下の制限を検討できる。

  • 関数は pure。
  • lexical closure は許可。
  • 引数は thunk として渡す。
  • 関数本体は必要になるまで評価しない。
  • 関数値は opaque。
  • 関数同士の & は、同一関数参照以外は conflict。
  • 関数値は最終データとして出力できない。
  • 再帰は cycle error として扱う、または v1 では禁止する。