fluorite12

オブジェクトリテラル {entry; ...}

{ } はオブジェクトを作るリテラルです。

括弧内には、 ; で区切って0個以上のエントリーを書くことができます。

{ } は文レベルの場所に書かれても、コードブロックではなくオブジェクトリテラルとして振舞います。

$ flc '{a: 1; b: 2}'
# {a:1;b:2}

; で区切られた項が key: value の形式であることは強制ではなく、実際には2要素の配列、およびそのストリームを受け付けます。

エントリー演算子 : は、オブジェクトリテラルとは本質的に無関係な、両辺を2要素の配列にする演算子です。

$ flc '{1 .. 3 | "Item$_": _ * 10; 4 .. 6 | ["Item$_", _ * 100]}'
# {Item1:10;Item2:20;Item3:30;Item4:400;Item5:500;Item6:600}

オブジェクトリテラル内での ; の記述は柔軟です。

項の前後や中間に ; を余計に多く書いても問題ありません。

また、改行は ; の代わりになります。

$ flc '{
  a: 1
  b: 2
  ; ; ; c: 3; ; ;
}'
# {a:1;b:2;c:3}

オブジェクトリテラル内での変数宣言

オブジェクトリテラル内で変数を宣言した場合、その変数はオブジェクトのエントリーに含まれつつ、オブジェクトリテラル内からも名前でアクセスできます。

$ flc '
  {
    fruit := "apple"
    result: fruit & fruit
  }
'
# {fruit:apple;result:appleapple}

変数にアクセスした時点で初期化される

オブジェクトリテラル内で宣言された変数にアクセスすると、そのエントリはその時点でオブジェクトに代入されます。

$ flc '
  {
    result: fruit & fruit
    fruit := "apple"
  }
'
# {fruit:apple;result:appleapple}

この例では、 result の値を計算する時点では fruit にはまだ値が設定されていないため、アクセスした時点で初期化が行われます。

オブジェクトのストリーム化 object()

配列のストリーム化と似ていますが、こちらは各エントリーのキーと値で構成される配列のストリームを返します。

$ flc '{a: 1; b: 2; c: 3}()'
# [a;1]
# [b;2]
# [c;3]

以下は、オブジェクトを、各キーの末尾に z を付け、各値を10倍したオブジェクトにする例です。

$ flc '{a: 1; b: 2; c: 3}() | (_.0 & "z": _.1 * 10) >> TO_OBJECT'
# {az:10;bz:20;cz:30}

オブジェクトの要素アクセス object(key)

配列の要素アクセスと概ね同じですが、キーには文字列が使われます。

$ flc '{a: 1; b: 2; c: 3}("b")'
# 2

$ flc '{a: 1; b: 2; c: 3}("b", "a")'
# 2
# 1

$ flc '"b", "a", "c" >> {a: 1; b: 2; c: 3}'
# 2
# 1
# 3

オブジェクトの要素アクセスは実際には _() メソッドの呼び出しであり、オーバーライドができます。

これにより関数のように振舞うオブジェクトを作ることができます。

$ flc '
  adder := {
    `_()`: this, a, b -> a + b
  }{}
  adder(10; 20)
'
# 30

$ flc '
  adder := {
    `_()`: {
      `_()`: this2, this1, a, b -> a + b
    }{}
  }{}
  adder(10; 20)
'
# 30

オブジェクト要素への代入

object.key = value でオブジェクトの要素に値を代入できます。

$ flc '
  object := {
    a: "one"
    b: "two"
    c: "three"
  }

  object.b = 99999

  object
'
# {a:one;b:99999;c:three}

キーがそのオブジェクトにまだ存在しない場合は新たに追加されます。