組み込み定数は、コード上で定義することなく利用可能な、言語機能に付属する定数です。

組み込み定数は大文字および_のみを使って定義されます。

組み込みの関数も組み込み定数と同じメカニズムによって提供されます。

組み込みオブジェクトのクラス定数#

各種組み込みオブジェクトのクラスを参照できます。

  • VALUE
  • NULL_CLASS
  • INT
  • DOUBLE
  • BOOLEAN
  • STRING
  • REGEX
  • ARRAY
  • OBJECT
  • FUNCTION
  • STREAM
  • PROMISE
  • BLOB
  • ERROR

定数#

各種、特別な値を表す定数です。

定数 意味
NULL N NULL値
TRUE T
FALSE F
EMPTY E 空のストリーム
LOOP 無限にNULLを生成するストリーム

文字列系の組み込み定数です。

定数 意味
LT <
GT >
AMP &
APOS '
QUOT "
BOM "\uFEFF" (Byte Order Mark)

ストリーム系関数#

REVERSEストリームを逆順にする#

REVERSE(stream: STREAM<VALUE>): STREAM<VALUE>

第1引数のストリームの要素を逆順にしたストリームを返します。

$ xa 'REVERSE(1 .. 3)'
# 3
# 2
# 1

SHUFFLEストリームをランダムな順序にする#

<T> SHUFFLE(stream: T,): T,

streamの要素をランダムに並べ替えたストリームを返します。

DISTINCT / UNIQストリームの重複要素を除去#

ストリームから重複する要素を取り除いたストリームを返します。

UNIQDISTINCTの別名であり、同一の動作を持ちます。

DISTINCTは、2種類の呼び出し方があります。

要素そのもので重複判定#

DISTINCT(stream: STREAM<VALUE>): STREAM<VALUE>

1引数で呼び出した場合、そのストリームの要素そのものを使って重複を判定し、重複を除去したストリームを返します。

$ xa '1, 2, 3, 3, 3, 2, 1, 0 >> DISTINCT'
# 1
# 2
# 3
# 0

キー取得関数による重複判定#

DISTINCT(by: keyGetter: VALUE -> VALUE; stream: STREAM<VALUE>): STREAM<VALUE>

第1引数がbyパラメータである場合、第2引数の各要素に対してkeyGetter関数を適用し、その結果で重複を判定します。

以下の例では、各要素を10で割った余りで重複を判定しています。

$ xa '13, 21, 24, 33, 31, 34 >> DISTINCT[by: x -> x % 10]'
# 13
# 21
# 24

JOINストリームを文字列に連結#

JOIN([separator: STRING; ]stream: STREAM<STRING>): STRING

第2引数のストリームの各要素を第1引数のセパレータで連結した文字列を返します。第1引数を省略した場合は,が使用されます。

$ xa 'JOIN("|"; "a", "b", "c")'
# a|b|c

$ xa 'JOIN("a", "b", "c")'
# a,b,c

セパレータやストリームの各要素は文字列化されます。

$ xa 'JOIN(0; 1, "b", {`&_`: _ -> "c"}{})'
# 10b0c

部分適用とともに用いることで、パイプチェーンに組み込みやすくなります。

$ xa '1 .. 3 | _ * 10 >> JOIN["|"]'
# 10|20|30

SPLIT文字列をストリームに分割#

SPLIT([separator: [by: ]STRING; ][limit: [limit: ]INT; ]string: STRING): STREAM<STRING>

stringseparatorで分割し、各部分をストリームとして返します。separatorを省略した場合は,が使用されます。

パイプ演算子との親和性のために配列ではなくストリームとして返されることに注意してください。

SPLITは概念的にJOINと逆の操作を行います。

separatorstringは文字列化されて評価されます。

$ xa 'SPLIT("|"; "a|b|c")'
# a
# b
# c

$ xa 'SPLIT("a,b,c")'
# a
# b
# c

limitが指定された場合、最大でlimit個の要素に分割され、limit個目の要素には残りの文字列全体が含まれます。

$ xa 'SPLIT("|"; limit: 2; "a|b|c|d")'
# a
# b|c|d

部分適用とともに用いることでパイプチェーンに組み込みやすくなります。

$ xa '"10|20|30" >> SPLIT["|"] | +_ / 10'
# 1.0
# 2.0
# 3.0

LINES文字列を行ごとに分割#

LINES(string: STRING): STREAM<STRING>

stringを改行で分割し、各行をストリームとして返します。

結果の各行からは改行文字が除去されます。

stringの末尾に改行がある場合、その改行は1個だけ無視されます。

$ xa 'LINES("A\nB\nC") >> TO_ARRAY >> JSONS'
# ["A","B","C"]

$ xa 'LINES("A\nB\nC\n") >> TO_ARRAY >> JSONS'
# ["A","B","C"]

$ xa 'LINES("A\nB\nC\n\n") >> TO_ARRAY >> JSONS'
# ["A","B","C",""]

空文字列の場合は空ストリーム、1個の改行のみの場合は空文字列1個のストリームを返します。

$ xa 'LINES("") >> TO_ARRAY >> JSONS'
# []

$ xa 'LINES("\n") >> TO_ARRAY >> JSONS'
# [""]

改行文字(LF、CR、CRLF)はすべて認識されます。

$ xa 'LINES("A\rB\nC\r\nD")'
# A
# B
# C
# D

LINESD行ストリームを文字列に連結#

LINESD(lines: STREAM<STRING>): STRING

linesの各要素に改行を付加して連結した文字列を返します。

$ xa '"A", "B", "C" >> LINESD >> JSON'
# "A\nB\nC\n"

空ストリームの場合、空文字列を返します。

$ xa ', >> LINESD >> JSON'
# ""

LINESDは概念的にLINESと逆の操作を行います。

末尾が改行で終わる文字列をLINESで分割してからLINESDで連結すると、改行文字などの違いを除き、元の文字列に戻ります。

$ xa '"A\nB\nC\n" >> LINES >> LINESD >> JSON'
# "A\nB\nC\n"

KEYSオブジェクトのキーのストリームを取得#

KEYS(object: STREAM<OBJECT>): STREAM<STRING>

objectのキーのストリームを返します。

$ xa 'KEYS({a: 1; b: 2; c: 3})'
# a
# b
# c

objectがストリームの場合、各要素のオブジェクトのキーを順番に返す平坦化されたストリームを返します。

$ xa 'KEYS({a: 1; b: 2}, {c: 3; d: 4})'
# a
# b
# c
# d

VALUESオブジェクトの値のストリームを取得#

VALUES(object: OBJECT): STREAM<VALUE>

第1引数のオブジェクトの値のストリームを返します。

$ xa 'VALUES({a: 1; b: 2; c: 3})'
# 1
# 2
# 3

INVERT値からキーを引くオブジェクトを返す#

INVERT(object: OBJECT<VALUE>): OBJECT<STRING>

objectの各エントリーの値からキーを引くオブジェクトを生成して返します。

$ xa 'INVERT({a: "apple"; b: "banana"; c: "cherry"})'
# {apple:a;banana:b;cherry:c}

値はキーとして扱ううえで一度文字列化されます。

$ xa '
  Fruit := {
    new: value -> Fruit{value: value}
    `&_`: this -> "Fruit[$(this.value)]"
  }
  INVERT({
    a: Fruit.new("apple")
    b: Fruit.new("banana")
    c: Fruit.new("cherry")
  })
'
# {Fruit[apple]:a;Fruit[banana]:b;Fruit[cherry]:c}

値が重複していた場合、その中のいずれかのエントリーのキーがマッピングされます。

$ xa '
  object   := {a: "apple"; b: "banana"; c: "apple"}
  inverted := INVERT(object)
  inverted.apple >> object
'
# apple

どのキーがマッピングされるかは未定義です。

SUMストリームの要素の合計#

SUM(numbers: STREAM<NUMBER>): NUMBER

第1引数のストリームの各要素を加算した値を返します。

$ xa 'SUM(1 .. 3)'
# 6

MINストリームの最小値#

MIN(numbers1: STREAM<NUMBER>[; numbers2: STREAM<NUMBER>]): NUMBER

numbers1およびnumbers2の各要素のうち、最小の値を返します。

要素が1個も無い場合はNULLを返します。

$ xa 'MIN(3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5)'
# 1

$ xa 'MIN(,)'
# NULL

$ xa '3 MIN 5'
# 3

MAXストリームの最大値#

MAX(numbers1: STREAM<NUMBER>[; numbers2: STREAM<NUMBER>]): NUMBER

numbers1およびnumbers2の各要素のうち、最大の値を返します。

要素が1個も無い場合はNULLを返します。

$ xa 'MAX(3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5)'
# 9

$ xa 'MAX(,)'
# NULL

$ xa '3 MAX 5'
# 5

COUNTストリームの要素数#

COUNT(stream: STREAM<VALUE>): INT

第1引数のストリームの要素数を返します。

非ストリームの場合、1を返します。

$ xa 'COUNT(1, 2, 3)'
# 3

$ xa 'COUNT(1)'
# 1

$ xa 'COUNT(,)'
# 0

AND / ALLすべてが真かを判定#

<T> AND(boolean1: STREAM<T>[; boolean2(): STREAM<T>]): T | BOOLEAN

渡されたすべての要素が真であるかどうかを判定します。

要素が一つも無かった場合、真を返します。

ALLANDの別名であり、同一の動作を持ちます。

$ xa 'AND(TRUE; TRUE)'
# TRUE

$ xa 'AND(TRUE; FALSE)'
# FALSE

$ xa 'AND(FALSE; FALSE)'
# FALSE

$ xa 'TRUE AND FALSE'
# FALSE

$ xa 'AND(TRUE, FALSE; TRUE, FALSE)'
# FALSE

$ xa '1 .. 50 | _ != 39 >> AND'
# FALSE

より厳密には、この関数は最初に見つかった論理値化が偽である要素を返し、見つからなかった場合はTRUEを返します。

最初に論理値化が偽である要素が見つかった時点で、以降のストリームのイテレーションと要素の論理値化はスキップされます。

&&演算子と同様に、第1引数の評価結果が確定した時点で第2引数の評価を省略します。

$ xa '1, "a", TRUE, 0, "b" >> AND'
# 0

$ xa '1, "a", TRUE, 2, "b" >> AND'
# TRUE
$ xa '
  list := []

  5 .. -5 | (
    list += _
    _
  ) >> AND

  list
'
# [5;4;3;2;1;0]
$ xa '
  list := []

  (
    list += "left"
    FALSE
  ) AND (
    list += "right"
    TRUE
  )

  list
'
# [left]

OR / ANYいずれかが真かを判定#

<T> OR(boolean1: STREAM<T>[; boolean2(): STREAM<T>]): T | BOOLEAN

渡された要素がいずれか一つでも真であるかどうかを判定します。

要素が一つも無かった場合、偽を返します。

ANYORの別名であり、同一の動作を持ちます。

$ xa 'OR(TRUE; TRUE)'
# TRUE

$ xa 'OR(TRUE; FALSE)'
# TRUE

$ xa 'OR(FALSE; FALSE)'
# FALSE

$ xa 'TRUE OR FALSE'
# TRUE

$ xa 'OR(TRUE, FALSE; TRUE, FALSE)'
# TRUE

$ xa '1 .. 50 | _ != 39 >> OR'
# TRUE

それ以外の性質は、AND関数に準じます。

GETインデックスによる要素の取得#

<T> GET(indices: STREAM<INT>; stream: STREAM<T>): STREAM<T | NULL>

indicesに対応するインデックスの、streamの要素を返します。

インデックスは0から始まります。

負のインデックスを渡した場合は、エラーをスローします。

該当するインデックスが存在しない場合は、NULLを返します。

indicesがストリームの場合、各インデックスに対応する要素のストリームを返します。

$ xa 'GET(1; 0, 10, 20)'
# 10

$ xa 'GET(5; 0, 10, 20)'
# NULL

$ xa 'GET(0, 2; 0, 10, 20)'
# 0
# 20

$ xa '0, 10, 20, 30, 40 >> GET[3, 0, 2, 2, 5]'
# 30
# 0
# 20
# 20
# NULL

FIRSTストリームの先頭要素を取得#

FIRST(stream: STREAM<VALUE>): VALUE

第1引数のストリームの先頭要素を返します。ストリームが空の場合はNULLを返します。

非ストリームを渡した場合は、その値をそのまま返します。

$ xa 'FIRST(4, 5, 6)'
# 4

$ xa 'FIRST(4)'
# 4

$ xa 'FIRST(,)'
# NULL

LASTストリームの末尾要素を取得#

LAST(stream: STREAM<VALUE>): VALUE

第1引数のストリームの末尾要素を返します。ストリームが空の場合はNULLを返します。

非ストリームを渡した場合は、その値をそのまま返します。

$ xa 'LAST(4, 5, 6)'
# 6

$ xa 'LAST(6)'
# 6

$ xa 'LAST(,)'
# NULL

SINGLEストリームの唯一の要素を取得#

<T> SINGLE(stream: STREAM<T>): T

第1引数のストリームの唯一の要素を返します。ストリームが空か複数要素を持つ場合はエラーをスローします。

非ストリームを渡した場合は、その値をそのまま返します。

$ xa 'SINGLE(4, 5, 6) !? "Error"'
# Error

$ xa 'SINGLE(6)'
# 6

$ xa 'SINGLE(,) !? "Error"'
# Error

SORTストリームを昇順にソートする#

ストリームを昇順にソートします。

SORTは、3種類の呼び出し方があります。

自然順序付けによるソート#

SORT(stream: STREAM<VALUE>): STREAM<VALUE>

1引数で呼び出した場合、そのストリームの要素を昇順にソートしたストリームを返します。

$ xa '3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5 >> SORT >> JOIN[" "]'
# 1 1 2 3 3 4 5 5 5 6 9

比較関数によるソート#

SORT(comparator: VALUE, VALUE -> INT; stream: STREAM<VALUE>): STREAM<VALUE>

2引数で呼び出した場合、第1引数の比較関数を使用して第2引数のストリームをソートします。

以下の例では、各要素を3で割った余りでソートしています。

$ xa '1 .. 9 >> SORT[a, b -> a % 3 <=> b % 3] >> JOIN[" "]'
# 3 6 9 1 4 7 2 5 8

キー取得関数によるソート#

SORT(by: keyGetter: VALUE -> VALUE; stream: STREAM<VALUE>): STREAM<VALUE>

第1引数がbyパラメータである場合、第2引数の各要素に対してkeyGetter関数を適用し、その結果を比較してソートします。

以下の例では、各要素を3で割った余りでソートしています。

$ xa '1 .. 9 >> SORT[by: x -> x % 3] >> JOIN[" "]'
# 3 6 9 1 4 7 2 5 8

SORTRストリームを降順にソートする#

SORTR(stream: STREAM<VALUE>): STREAM<VALUE>

SORTR(comparator: VALUE, VALUE -> INT; stream: STREAM<VALUE>): STREAM<VALUE>

SORTR(by: keyGetter: VALUE -> VALUE; stream: STREAM<VALUE>): STREAM<VALUE>

ストリームを降順にソートします。

ソートが降順である点を除き、SORT関数と同じです。

$ xa '3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5 >> SORTR >> JOIN[" "]'
# 9 6 5 5 5 4 3 3 2 1 1

INDEXEDインデックス付きのストリームに変換#

<T> INDEXED(stream: STREAM<T>): STREAM<[INT; T]>

streamの各要素に対して0から始まるインデックスを付与した2要素配列のストリームを返します。

$ xa '"a", "b", "c" >> INDEXED'
# [0;a]
# [1;b]
# [2;c]

TRANSPOSE / ZIP配列のストリームを転置#

<T> TRANSPOSE([fill: [fill: ]T; ]table: STREAM<ARRAY<T>>): STREAM<ARRAY<T>>

配列のストリームを受け取り、行と列を入れ替えた配列のストリームを返します。

ZIPTRANSPOSEの別名であり、同一の動作を持ちます。

$ xa '
  TRANSPOSE(
    [1;2;3],
    [4;5;6],
  )
'
# [1;4]
# [2;5]
# [3;6]

fillパラメータを指定した場合、短い配列をfillでパディングします。

fillパラメータを指定しない場合、配列の長さが異なるとエラーをスローします。

$ xa '
  [1;2;3],
  [4;5],
  >> TRANSPOSE[fill: 0]
'
# [1;4]
# [2;5]
# [3;0]

以下の例では、keysvaluesという2つの配列からオブジェクトを構成します。

$ xa '
  keys := ["name", "age", "city"]
  values := ["Alice", 30, "Tokyo"]
  ZIP(keys, values) >> TO_OBJECT
'
# {name:Alice;age:30;city:Tokyo}

GROUPストリームをキーでグループ化#

<T, K> GROUP([keyGetter: [by: ]T -> K; ]stream: STREAM<T>): STREAM<[K; ARRAY<T>]>

streamの各要素に対してkeyGetterを適用し、同一のキーとなる値を配列でエントリーにまとめてストリームで返します。

keyGetterを省略した場合は要素そのものをキーとしてグループ化します。

エントリーの配列は、最初にそのキーが現れた順序になります。

$ xa '"apple", "cherry","banana", "banana", "apple" >> GROUP'
# [apple;[apple;apple]]
# [cherry;[cherry]]
# [banana;[banana;banana]]

$ xa '
  {category: "fruit" ; value: "apple" },
  {category: "fruit" ; value: "banana"},
  {category: "animal"; value: "cat"   },
  >> GROUP[by: x -> x.category]
'
# [fruit;[{category:fruit;value:apple};{category:fruit;value:banana}]]
# [animal;[{category:animal;value:cat}]]

キーが文字列化可能な場合、TO_OBJECT関数によって簡単にオブジェクトにまとめることができます。

$ xa '
  object := (
    {category: "fruit" ; value: "apple" },
    {category: "fruit" ; value: "banana"},
    {category: "animal"; value: "cat"   },
    >> GROUP[by: x -> x.category]
    >> TO_OBJECT
  )
  object.fruit() | _.value
'
# apple
# banana

CHUNKストリームを一定サイズの配列に分割#

CHUNK(size: NUMBER; stream: STREAM<VALUE>): STREAM<ARRAY<VALUE>>

第2引数のストリームの要素を第1引数で指定したサイズごとにまとめた配列のストリームを返します。

$ xa '1, 2, 3, 4, 5 >> CHUNK[2]'
# [1;2]
# [3;4]
# [5]

SLIDEストリームをスライディングウィンドウに分割#

SLIDE(size: NUMBER; stream: STREAM<VALUE>): STREAM<ARRAY<VALUE>>

第2引数のストリームの要素を第1引数で指定したサイズのスライディングウィンドウに分割した配列のストリームを返します。 要素数がサイズに満たない場合は空ストリームになります。

$ xa '1, 2, 3, 4, 5 >> SLIDE[3]'
# [1;2;3]
# [2;3;4]
# [3;4;5]

TAKEストリームの先頭を取得#

TAKE(count: INT; stream: STREAM<VALUE>): STREAM<VALUE>

第2引数のストリームから先頭count個の要素を取り出したストリームを返します。

$ xa '1, 2, 3 >> TAKE[2]'
# 1
# 2

TAKERストリームの末尾を取得#

TAKER(count: INT; stream: STREAM<VALUE>): STREAM<VALUE>

第2引数のストリームから末尾count個の要素を取り出したストリームを返します。

$ xa '1, 2, 3 >> TAKER[2]'
# 2
# 3

DROPストリームの先頭を破棄#

DROP(count: INT; stream: STREAM<VALUE>): STREAM<VALUE>

第2引数のストリームから先頭count個の要素を取り除いたストリームを返します。

$ xa '1, 2, 3 >> DROP[2]'
# 3

DROPRストリームの末尾を破棄#

DROPR(count: INT; stream: STREAM<VALUE>): STREAM<VALUE>

第2引数のストリームから末尾count個の要素を取り除いたストリームを返します。

$ xa '1, 2, 3 >> DROPR[2]'
# 1

FILTER / GREPストリームを条件で抽出#

FILTER(predicate: [by: ]VALUE -> BOOLEAN; stream: STREAM<VALUE>): STREAM<VALUE>

streamの各要素にpredicateを適用し、真となった要素のみを含むストリームを返します。

GREPFILTERの別名であり、同一の動作を持ちます。

$ xa '1 .. 5 >> FILTER [ x => x % 2 == 1 ]'
# 1
# 3
# 5

$ xa '1 .. 5 >> FILTER[by: x -> x % 2 == 1]'
# 1
# 3
# 5

REDUCEストリームの要素を累積する#

REDUCE(function: VALUE, VALUE -> VALUE; stream: STREAM<VALUE>): VALUE

REDUCEstreamの隣り合った要素をfunctionによって累積し、一つの値に集約する関数です。

REDUCEは、しばしば部分適用によってストリームを処理する関数として用いられます。

$ xa 'REDUCE(a, b -> a + b; 1 .. 4)'
# 10

$ xa '1 .. 4 >> REDUCE[a, b -> a + b]'
# 10

この例は、1から4までのすべての隣接する値に対してa + bを適当します。

すなわち、1 + 2 + 3 + 4と同じです。


ストリームの要素が1つしかない、もしくはストリームでない場合、その要素をそのまま返します。

$ xa '1 >> REDUCE[a, b -> a + b]'
# 1

ストリームが空の場合、NULLを返します。

$ xa ', >> REDUCE[a, b -> a + b]'
# NULL

TO_STRING文字列化#

TO_STRING(value: VALUE): STRING

値を文字列に変換します。

&value演算子と同じ動作をします。

$ xa 'TO_STRING(123)'
# 123

$ xa '1, 2, 3 >> TO_STRING'
# 123

TO_BOOLEAN論理値化#

TO_BOOLEAN(value: VALUE): BOOLEAN

値を論理値に変換します。

?value演算子と同じ動作をします。

$ xa 'TO_BOOLEAN("")'
# FALSE

$ xa 'TO_BOOLEAN("a")'
# TRUE

$ xa 'FALSE, TRUE, FALSE >> TO_BOOLEAN'
# TRUE

TO_ARRAYストリームを配列に変換#

ARRAY(stream: STREAM<VALUE>): ARRAY<VALUE>

第1引数のストリームの各要素を配列に変換します。

$ xa 'TO_ARRAY(1 .. 3)'
# [1;2;3]

TO_OBJECTエントリーのストリームをオブジェクトに変換#

OBJECT(stream: STREAM<[STRING; VALUE]>): OBJECT

第1引数のストリームの各要素をエントリーとしてオブジェクトに変換します。

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

::LET / LET値をブロックに渡してブロックの戻り値を返す#

<I, O> I::LET(block: I -> O): O

<I, O> LET(receiver: I; block: I -> O): O

レシーバーの値をblockに渡して実行し、blockの戻り値を返す拡張関数です。

メソッドチェーンの途中で値を変換するのに便利です。

$ xa '"apple"::LET ( s => s & "banana" )::UC()'
# APPLEBANANA

::LETは連鎖して使用することもできます。

$ xa '"apple"::LET ( s => s & "banana" )::LET ( s => s::UC() )'
# APPLEBANANA

ストリームに対する使用#

ストリームはすべてのメソッドを各要素に対して適用する性質上、::LET拡張メソッドを利用することができません。

$ xa '
  Object := {
    new: value -> Object{value: value}
    LET: this, block -> "LET!"
  }
  stream := Object.new(1), Object.new(2), Object.new(3)

  stream::LET ( s => s.value >> SUM )
'
# LET!
# LET!
# LET!

そのため、代わりにストリームも取れるLET関数を使用します。

2文字長い代わりに、stream::(LET) ( s => ... )という形で概ね同じように動作します。

$ xa '
  Object := {
    new: value -> Object{value: value}
    LET: this, block -> "LET!"
  }
  stream := Object.new(1), Object.new(2), Object.new(3)

  stream::(LET) ( s => s.value >> SUM )
'
# 6

::ALSO / ALSO値をブロックに渡して元の値を返す#

<T> T::ALSO(block: T -> VALUE): T

<T> ALSO(receiver: T; block: T -> VALUE): T

レシーバーの値をblockに渡して実行し、レシーバーの値を返す拡張関数です。

1度の呼び出しにつき、blockの副作用も丁度1度だけ発生します。

メソッドチェーンの途中で値を使用や改変するのに便利です。

$ xa '
  variable := ""
  "apple"::ALSO ( s =>
    variable = variable & s
  )
  variable
'
# apple

その他の性質は概ねLETと同じです。

LAZY遅延評価・キャッシュ関数#

<T> LAZY(initializer: () -> T): () -> T

遅延評価とキャッシュをする関数を返します。

initializerLAZYの戻り値の関数の初回呼び出し時に1度だけ呼び出され、その結果はキャッシュされます。

initializerがストリームを返した場合、そのストリームは解決されます。

$ xa -q '
  counter := 1
  lazy := LAZY ( =>
    counter++
    counter
  )
  OUT << lazy()
  OUT << lazy()
  OUT << lazy()
'
# 2
# 2
# 2

この関数は委譲変数と組み合わせると関数呼び出し演算子を省略できて便利です。

$ xa -q '
  time := 0
  \now := LAZY ( => time )

  time = 100
  OUT << now
  time = 200
  OUT << now
'
# 100
# 100

LAZY2遅延評価・キャッシュ関数#

<T> LAZY2(initializer(): T): () -> T

遅延評価とキャッシュをする関数を返します。

LAZYと同等ですが、引数を式渡し引数として受け取ります。

$ xa -q '
  counter := 1
  lazy := LAZY2 ((
    counter++
    counter
  ))
  OUT << lazy()
  OUT << lazy()
  OUT << lazy()
'
# 2
# 2
# 2