Decodal/doc/manual/souce/language/operators.md
2026-06-19 01:01:04 +09:00

6.4 KiB

演算子

この章では、Decodal の演算子の意味を定義する。

演算子一覧

演算子 種類 対象 結果 / 意味
. object.field field reference object / abstract object field value
call fn(arg) function call function function result
! !expr unary logical concrete Bool concrete Bool
- -expr unary arithmetic concrete Int / Float negated number
* lhs * rhs arithmetic concrete Int / Float numeric product
/ lhs / rhs arithmetic concrete Int / Float Float quotient
+ lhs + rhs arithmetic concrete Int / Float numeric sum
- lhs - rhs arithmetic concrete Int / Float numeric difference
++ lhs ++ rhs array concat concrete arrays concatenated array
== lhs == rhs equality concrete scalar concrete Bool
!= lhs != rhs equality concrete scalar concrete Bool
< lhs < rhs ordering concrete Int / Float concrete Bool
<= lhs <= rhs ordering concrete Int / Float concrete Bool
> lhs > rhs ordering concrete Int / Float concrete Bool
>= lhs >= rhs ordering concrete Int / Float concrete Bool
> > value comparison constraint numeric constraint value abstract constraint
>= >= value comparison constraint numeric constraint value abstract constraint
< < value comparison constraint numeric constraint value abstract constraint
<= <= value comparison constraint numeric constraint value abstract constraint
&& lhs && rhs logical concrete Bool short-circuit AND
` ` `lhs
& lhs & rhs composition value / constraint / object constraint-preserving composition
// lhs // rhs patch object / value right-biased structural patch
default base default fallback default abstract value materialization fallback

concrete scalarStringBoolIntFloat を指す。

優先順位

優先順位は高い順に以下である。

  1. 関数呼び出しとフィールド参照
  2. unary ! -
  3. * /
  4. + -
  5. ++
  6. == != < <= > >=
  7. &&
  8. ||
  9. &
  10. //
  11. default

同じ優先順位の二項演算子は左結合である。 default は右結合である。

Arithmetic operators

+ - * / は具体的な Int / Float に対する四則演算である。 詳しくは Arithmetic Expression を参照する。

Array concat operator

++ は concrete array 同士を連結する演算子である。 要素は変換されず、左辺の要素の後に右辺の要素が並ぶ。

["read", "write"] ++ ["admin"]

Logical and comparison operators

! && || は concrete Bool に対する論理演算である。 &&|| は短絡評価される。

== != は concrete scalar value を比較する。 < <= > >= は concrete numeric value を比較する。 詳しくは Logical and Comparison Expressions を参照する。

&: 制約合成

& は値・制約・構造を合成する演算子である。

A & B

基本規則:

  • 両方が制約なら、両方を満たす制約になる。
  • 制約と具体値なら、具体値が制約を満たす必要がある。
  • 両方が同じ具体値なら、その値になる。
  • 両方が異なる具体値なら conflict になる。
  • 両方が object なら、フィールドごとに合成する。
  • 同じフィールドが両方にある場合、そのフィールド値を & で合成する。
  • 矛盾が発生した場合はエラーになる。

例:

Port = Int & >= 1 & <= 65535;
NarrowedPort = Port & > 443;

MyConfig = {
    port = NarrowedPort default 8080;
};

Config = MyConfig & {
    port = 8000;
};

Config.port は概念的には以下になる。

NarrowedPort & 8000

8000NarrowedPort を満たすため成功する。

一方、以下は失敗する。

BadConfig = MyConfig & {
    port = 80;
};

80> 443 を満たさないためである。

//: patch 合成

// は右辺優先の構造的 patch 演算子である。 & が制約を保った合成であるのに対し、// は設定やスキーマを上書き・変更するために使う。

A // B

基本規則:

  • 両方が object なら、フィールドごとに再帰的に patch する。
  • 同じフィールドが object/object なら、さらに再帰的に patch する。
  • 同じフィールドが object/object 以外なら、右辺で置き換える。
  • 左辺にしかないフィールドは保持する。
  • 右辺にしかないフィールドは追加する。
  • 配列はデフォルトでは右辺で置き換える。
  • 関数値はデフォルトでは右辺で置き換える。

つまり // は shallow merge ではなく deep patch とする。

Base = {
    feature_hoge = {
        enable = Bool default true;
        fuga = Int default 10;
    };
};

Patched = Base // {
    feature_hoge = {
        enable = false;
    };
};

Patched は以下に相当する。

{
    feature_hoge = {
        enable = false;
        fuga = Int default 10;
    };
}

ドットパスを使うと以下のようにも書ける。

Patched = Base // {
    feature_hoge.enable = false;
};

object 全体の置換

// が deep patch である場合、object 全体を置き換えたいときの escape hatch が必要になる。

候補として、replace(...) を組み込み関数として提供する。

Replaced = Base // {
    feature_hoge = replace({
        enable = false;
    });
};

この場合、feature_hoge は再帰 patch されず、右辺の object に丸ごと置き換わる。

&// の使い分け

& は制約を満たす具体化に使う。

ValidConfig = MyConfig & {
    port = 8000;
};

// は既存構造の上書きや変形に使う。

ModifiedSchema = MyConfig // {
    port = Int default 9000;
};

// は右辺優先の patch であり、左辺の制約を常に保持するとは限らない。 制約を保持したい場合は & を使う。