比較#

数値同士や文字列同士の比較、特定の要素が配列に含まれているかといった様々な判定を行うことができます。

比較系演算子の結合#

比較系演算子同士の結合は特殊で、以下の手順を踏みます。

  1. すべての比較系演算子について、左右の辺による比較を行う
  2. それらの論理積を取る

例えば、3 <= x <= 5は、まず3 <= xを計算し、次にx <= 5を計算し、最後にその論理積3 <= x && x <= 5を取ります。

これにより、比較の連鎖を簡潔に記述できます。

$ xa '3 <= 4 <= 5'
# TRUE

$ xa '3 <= 10 <= 5'
# FALSE

この仕様の対象となるのは、以下の演算子です。

  • > < >= <= == != === !== @ !@ ?= !?=

比較演算子#

比較演算子には以下のものがあります。

演算子 意味
left > right leftがrightより大きいか否かを返す
left < right leftがrightより小さいか否かを返す
left >= right leftがright以上であるか否かを返す
left <= right leftがright以下であるか否かを返す
$ xa '[1 > 2, 2 > 2, 3 > 2]'
# [FALSE;FALSE;TRUE]

$ xa '[1 < 2, 2 < 2, 3 < 2]'
# [TRUE;FALSE;FALSE]

$ xa '[1 >= 2, 2 >= 2, 3 >= 2]'
# [FALSE;TRUE;TRUE]

$ xa '[1 <= 2, 2 <= 2, 3 <= 2]'
# [TRUE;TRUE;FALSE]

比較演算子のオーバーライド#

比較演算子の動作は、実際には宇宙船演算子の結果に基づいて判断しています。

宇宙船演算子のオーバーライドが行われると、各種比較演算子の動作も変わります。

等価系演算子#

等価演算子#

等価演算子left == rightは、両辺の値が等しいか否かを返します。

$ xa '[1 == 2, 2 == 2, 3 == 2]'
# [FALSE;TRUE;FALSE]

現在、数値や文字列などの一部の型においてのみ定義されています。


数値の型が異なる場合、同じ数値を表していても等しくないと判定されます。

$ xa '[BIG.of(1) == BIG.of(1), BIG.of(1) == 1, BIG.of(1) == 1.0]'
# [TRUE;FALSE;FALSE]

不等価演算子#

不等価演算子left != rightは、両辺の値が等しくないか否かを返します。

等価演算子の否定です。

$ xa '[1 != 2, 2 != 2, 3 != 2]'
# [TRUE;FALSE;TRUE]

厳密等価演算子#

厳密等価演算子left === rightは、両辺の値が厳密に等しいか否かを返します。

両辺の型が異なる場合は、常に厳密に等しくはないと判定します。

両辺の型が同じ場合は、型に応じて、次の表のように、厳密に等しいかを判定します。

型 名前 比較方法
INT 整数 内容の一致
DOUBLE 小数 内容の一致
BIG 任意精度整数 内容の一致
STRING 文字列 内容の一致
BOOLEAN 論理値 内容の一致
NULL NULL 内容の一致
REGEX 正規表現 内容の一致
OBJECT オブジェクト インスタンスの同一性
ARRAY 配列 インスタンスの同一性
BLOB BLOB インスタンスの同一性
STREAM ストリーム インスタンスの同一性
PROMISE Promise インスタンスの同一性
FUNCTION 関数 インスタンスの同一性
ERROR エラー インスタンスの同一性
$ xa -q '
  OUT << 1 === 1
  OUT << 1 === 1.0
  OUT << 1 === 2
'
# TRUE
# FALSE
# FALSE

$ xa -q '
  OUT << (
    a := [1, 2]
    a === a
  )
'
# TRUE

REGEXは、パターン文字列とフラグ文字列が等しい場合に一致します。

厳密等価演算子はオーバーライドできません。


DOUBLEのNaN同士は等しいと判定され、正のゼロと負のゼロは等しくないと判定されます。

$ xa '[NAN === DOUBLE.of("NaN"), 0.0 === -(0.0)]'
# [TRUE;FALSE]

厳密不等価演算子#

厳密不等価演算子left !== rightは、厳密等価演算子left === rightの否定版です。

$ xa -q '
  OUT << 1 !== 1
  OUT << 1 !== 1.0
  OUT << 1 !== 2
'
# FALSE
# TRUE
# TRUE

含有系演算子#

含有演算子#

含有演算子left @ rightは、leftがrightに含まれているか否かを返します。

右辺のタイプごとの挙動は以下の通りです。

右辺のタイプ 戻り値
文字列 左辺の文字列が右辺の文字列に含まれているか否か
配列 左辺の要素が右辺の配列に含まれているか否か
オブジェクト 左辺のキーが右辺のオブジェクトに含まれているか否か
$ xa '"bcd" @ "abcde"'
# TRUE

$ xa '"123" @ "abcde"'
# FALSE

$ xa '1 @ [1, 2, 3]'
# TRUE

$ xa '4 @ [1, 2, 3]'
# FALSE

$ xa '"a" @ {a: 1; b: 2; c: 3}'
# TRUE

$ xa '"d" @ {a: 1; b: 2; c: 3}'
# FALSE

含有演算子の働きは、文字列は部分文字列、配列は要素、オブジェクトはキーと、一貫していません。

否定含有演算子#

否定含有演算子left !@ rightは、leftがrightに含まれていないかどうかを返します。

含有演算子を使った!(left @ right)という表現と等価な動作をします。

$ xa '"bcd" !@ "abcde"'
# FALSE

$ xa '"123" !@ "abcde"'
# TRUE

含有演算子のオーバーライド#

含有演算子は、実際には右辺の値の_@_メソッドを呼び出し、論理値化したものを返す演算子です。

$ xa -q '
  Basket := {
    `_@_`: this, item -> item @ this.items
  }

  basket := Basket{items: ["apple", "orange", "banana"]}

  OUT << "Basket: $basket"
  "apple" @ basket && (OUT << "apple is in basket")
  "cherry" @ basket && (OUT << "cherry is in basket")
'
# Basket: {items:[apple;orange;banana]}
# apple is in basket

instanceOf系演算子#

instanceOf演算子#

instanceOf演算子left ?= rightは、leftがrightのインスタンスであるか否かを返します。

より厳密には、オブジェクトleftがrightと同一のインスタンスか、leftの継承チェーンのどこかにrightが存在するかを判定します。

$ xa -q '
  Animal := {}
  Human := Animal {}
  socrates := Human{}
  pythagoras := Human{}

  Animal ?= Animal && (OUT << "Animal is Animal")
  Human ?= Human && (OUT << "Human is Human")
  socrates ?= socrates && (OUT << "Socrates is Socrates")
  pythagoras ?= pythagoras && (OUT << "Pythagoras is Pythagoras")

  Human ?= Animal && (OUT << "Human is Animal")
  Animal ?= Human && (OUT << "Animal is Human")

  socrates ?= Human && (OUT << "Socrates is Human")
  Human ?= socrates && (OUT << "Human is Socrates")

  socrates ?= Animal && (OUT << "Socrates is Animal")
  Animal ?= socrates && (OUT << "Animal is Socrates")

  socrates ?= pythagoras && (OUT << "Socrates is Pythagoras")
  pythagoras ?= socrates && (OUT << "Pythagoras is Socrates")
'
# Animal is Animal
# Human is Human
# Socrates is Socrates
# Pythagoras is Pythagoras
# Human is Animal
# Socrates is Human
# Socrates is Animal

否定instanceOf演算子#

否定instanceOf演算子left !?= rightは、leftがrightのインスタンスでないか否かを返します。

instanceOf演算子を使った!(left ?= right)という表現と等価な動作をします。

$ xa -q '
  Animal := {}
  Human := Animal {}
  Dog := Animal {}
  socrates := Human{}

  socrates !?= Animal && (OUT << "Socrates is not Animal")
  socrates !?= Human && (OUT << "Socrates is not Human")
  socrates !?= Dog && (OUT << "Socrates is not Dog")
'
# Socrates is not Dog

宇宙船演算子#

宇宙船演算子<=>は左辺と右辺の大小関係を返す演算子です。

以下のように左右の大小関係と宇宙船演算子の戻り値の関係は、以下のようになります。

条件 戻り値
左辺 < 右辺 -1
左辺 = 右辺 0
左辺 > 右辺 1
$ xa '1 <=> 2'
# -1

$ xa '2 <=> 2'
# 0

$ xa '3 <=> 2'
# 1

数値同士の大小比較では、NaNは正の無限大を含むNaN以外のすべての数値より大きいものとして比較されます。

NaN同士を宇宙船演算子で比較した場合、0を返します。

$ xa 'DOUBLE.of("NaN") <=> DOUBLE.of("Infinity")'
# 1

$ xa 'DOUBLE.of("NaN") <=> DOUBLE.of("NaN")'
# 0

$ xa 'DOUBLE.of("NaN") > BIG.of(0)'
# TRUE

文字列同士を比較した場合は、辞書順で判定されます。

$ xa ' "a" <=> "b" '
# -1

$ xa ' "aa" <=> "a" '
# 1

宇宙船演算子のオーバーライド#

宇宙船演算子は、実際には左辺の値の_<=>_メソッドを呼び出し、その戻り値を返す演算子です。

$ xa '
  Person := {
    `_<=>_`: this, other -> this.age <=> other.age
  }

  alice := Person{age: 30}
  bob   := Person{age: 20}

  alice <=> bob
'
# 1

SORT関数などでの使用#

宇宙船演算子は、SORT関数などの比較関数として使用できます。

以下の例は、文字列の長さでソートする例です。

$ xa '
  (
    "apple",
    "banana",
    "cherry",
    "durian",
    "elderberry",
    "fig",
    "grape",
  ) >> SORT[a, b -> $#a <=> $#b]
'
# fig
# apple
# grape
# banana
# cherry
# durian
# elderberry

比較系関数#

CONTAINS / ::CONTAINS: 含有判定を行う関数#

CONTAINS(container: VALUE; content: VALUE): BOOLEAN

VALUE::CONTAINS(content: VALUE): BOOLEAN

CONTAINS関数および::CONTAINS拡張関数は、含有演算子@を関数および拡張関数の形式で呼び出すためのシンタックスシュガーです。

CONTAINS(container; content)、container::CONTAINS(content)、および中置関数呼び出しのcontainer CONTAINS contentはcontent @ containerと等価です。

$ xa ' CONTAINS("abcde"; "bcd") '
# TRUE

$ xa ' "abcde"::CONTAINS("bcd") '
# TRUE

$ xa ' "abcde" CONTAINS "bcd" '
# TRUE