LoginSignup
2
1

More than 5 years have passed since last update.

Julia で a == 1 && a == 2 && a == 3 を true にする

Last updated at Posted at 2018-01-24

StackOverflow で話題になった記事が他の言語版に派生しているようなので取調中の Julia 0.6.2 でも。

元ネタ: https://stackoverflow.com/questions/48270127/can-a-1-a-2-a-3-ever-evaluate-to-true

動的型付き言語ながら多重ディスパッチではスパルタンな型検査が行われる点などが気に入っている Julia ですが、マクロで AST (抽象構文木) を扱える言語なのでマクロで書き換えます。ありきたりですみません (だがタイトルは間違っていない!)。

macro 🍣(expr)
  if expr.head == :if && expr.args[1] == :(a == 1 && a == 2 && a == 3)
    expr.args[1] = :(true)
  end
  expr
end

a = 1
@🍣 if a == 1 && a == 2 && a == 3
  println("真")
else
  println("偽")
end
# ==> 真

(マクロ識別子の🍣に特に意味はありません) 見ての通り a==1 && a==2 && a==3 を条件に持つ if 文に付けられていたらその条件部分を固定値 true に置き換えるだけです。

三項演算子 exp? A: Bif 構文と解釈されるので使えます。

@🍣 (a == 1 && a == 2 && a == 3)? println("真"): println("偽")
# ==> 真

ただし println() 内で条件式を記述した AST はこのマクロでは機能しません。葉方向に下ってないからね。

@🍣 println(a == 1 && a == 2 && a == 3? "真": "偽")
# ==> 偽

条件文に付ければ OK

println(@🍣 a == 1 && a == 2 && a == 3? "真": "偽")
# ==> 真

寿司マクロが何をやっているかというと、構文解析で AST に展開された if の条件評価部分が args[1] であるため、そこを true に置き換えてコードを if(true) へ変換しているわけです (Julia の配列は 1-origin です)。

ちょっと長いですが if(...) 部分の AST ダンプはこのようになります。AST は Expr という型で表されます。また :(...) は中の構文を AST に変換します。

julia> dump(:(if(a == 1 && a == 2 && a == 3) true else false end))
Expr
  head: Symbol if
  args: Array{Any}((3,))
    1: Expr
      head: Symbol &&
      args: Array{Any}((2,))
        1: Expr
          head: Symbol call
          args: Array{Any}((3,))
            1: Symbol ==
            2: Symbol a
            3: Int64 1
          typ: Any
        2: Expr
          head: Symbol &&
          args: Array{Any}((2,))
            1: Expr
              head: Symbol call
              args: Array{Any}((3,))
                1: Symbol ==
                2: Symbol a
                3: Int64 2
              typ: Any
            2: Expr
              head: Symbol call
              args: Array{Any}((3,))
                1: Symbol ==
                2: Symbol a
                3: Int64 3
              typ: Any
          typ: Any
      typ: Any
    2: Expr
      head: Symbol block
      args: Array{Any}((2,))
        1: Expr
          head: Symbol line
          args: Array{Any}((2,))
            1: Int64 1
            2: Symbol REPL[34]
          typ: Any
        2: Bool true
      typ: Any
    3: Expr
      head: Symbol block
      args: Array{Any}((2,))
        1: Expr
          head: Symbol line
          args: Array{Any}((2,))
            1: Int64 1
            2: Symbol REPL[34]
          typ: Any
        2: Bool false
      typ: Any
  typ: Any

余談ですが、REPL や Jupyter Notebook など、Julia 環境は Unicode の タブ補完シーケンス をサポートしていて、\:sushi:Tab と入力すると 🍣 が入力されます。数学記号を入力しやすくするためですが ZWJ も使えて \:man:Tab \:skin-tone-5:Tab の順で 👨🏾 となります。スゴイ! (誰得)。

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1