ユーザ定義三元演算子


導入


三項演算子は非常に有用な構文表記法である
凝縮する意味.基本的に3つ
引数、そして構文的にそれは識別子です
つの部分に分割します.
例えば、
  • JavaScriptの条件a ? b : c
  • 範囲チェックa < b < c
  • SQL結合a JOIN b ON c
  • これはなぜ我々に似ている
    initバイナリ演算子(ibo)を好むので、彼らは
    容易に(または)呼ばれる
    associativity ).
    例えば、ほとんどの人は、AがBよりも読みやすく、理解しやすいと思います.
    エー
    Ba + b + c (+ (+ a b) c)なぜなら、IBOはとても重要だからです.
    Haskellのような最も機能的なプログラミング(FP)言語
    カスタムIboを定義するユーザーを許可します.
    例えば、
    -- pipe forward operator
    (|>) :: a -> (a -> b) -> b
    a |> f = f a
    
    -- example usage
    main = [1, 2, 3] 
      |> map (+2) 
      |> filter (>3) 
      |> print 
      |> putStrLn -- [4, 5]
    
    詳しく見るHaskell Infix Operator .

    バイナリ演算子のエミュレーション


    しかし、ユーザ定義の三項演算子になると、
    プログラミング言語のどれもメカニズムを提供しません.
    三重演算子は、ダブルを使用してエミュレートできますが
    Ibo、それはそれ自身の警告なしでありません.
    テイクthis example Haskellから:
    data Cond a = a :? a
    
    infixl 0 ?
    infixl 1 :?
    
    (?) :: Bool -> Cond a -> a
    True  ? (x :? _) = x
    False ? (_ :? y) = y
    
    test = 1 < 2 ? "Yes" :? "No"
    
    そのようなエミュレーションの警告は部分的な使用法です
    構文的に有効であるだけでなく、また
    意味的に有効です.
    例えば、我々はそれを省略することができます:?そして、コンパイラは文句を言わないでしょう.
    x = 1 < 2 ? "Yes"
    
    ユーザーエクスペリエンス(UX)の観点から、これは非常に悪いです.
    ユーザーは常に使用するように意図したので? 一緒に?: .

    MixFix演算子を使用したエミュレート


    Iboを使用する以外にも、MixFix演算子を使用して三項演算子をエミュレートできます.
    例えば、Agda :
    -- Example function name _if_else_ 
    -- (emulating Python's conditional operator)
    _if_else_ : {A : Set} -> Bool -> A -> A -> A
    x if true else y = x
    x if false else y = y
    
    そのようなアプローチの警告は、ユーザが
    構文解析を行う前に構文を検索する必要があります
    MixFix演算子で満たされたコードの一部.
    例えば、上記_if_else_ 演算子は以下のように定義できます:
    if_then_else_ : {A : Set} -> Bool -> A -> A -> A
    if x then true else y = x
    if x then false else y = y
    
    この場合、ユーザーは以下のコードを正確に解析することができませんif またはelse :
    x = a if b else c -- is this correct?
    y = if a then b else c -- or this?
    

    問題


    前述の三成分乳濁液のために
    演算子、私は許可するメカニズムを検索するための探求をしています
    ユーザ定義の三項演算子です.
  • はっきりしない(機械と人間の両方によって解決できる)
  • ユニバーサル(すべての三元演算子に適用可能)
  • インスピレーション


    私はしばらくの間、この質問を熟考しています
    それでも、私が読むまで、重要な進歩はありません
    ブックThe Relational Model of Database
    Management

    関係代数の発明者によって.Edgar. F. Codd .
    シータジョンズを表すための彼の表記法は独創的です.
    例えば、
    SQL
    エドガーの表記法X join Y on A join Z on B X [A] Y [B] Zこれについての独創的な部分は、彼が三項を扱うということです
    演算子としての演算子
    上の例では、バイナリ演算子[] , is
    装飾されたA , 違いを与える
    意味
    これは実際にシータジョインの数学表記にも関する.

    この場合、thethaシンボルは結合を飾っています
    シンボルを返します.
    バイナリ演算子として振る舞う.
    このアプローチの利点は
    演算子はバイナリ演算子のように振る舞う
    彼らは自然に一緒にチェーンすることができます.

    潜在的回答


    三者演算子がちょうどある考えを拡大することによって
    装飾された/汚染されたバイナリ演算子、私は最初にこの考えを持っています:
    三項演算子は以下の構文で定義できます:
    a X[ b ]Y c
    
    どこa , b and c は引数X[ and]Y は三項演算子の名前です.
    たとえば、範囲チェックを定義しましょう.
    -- Definition
    a <[ b ]< c = a < b && b < c
    
    -- Usage
    print (1 <[2]< 3) -- true
    print (1 <[3]< 2) -- false
    
    仮定する[ ] の構文では使用されません
    このような三項演算子の使用法を解析することができます
    簡単に.何故なら、ユーザーまたはマシンが[ or] , それから、彼らは三項演算子を予想することができます.
    しかしながら、上記の構文は明らかにあまりに騒がしいです
    ノイズを減らす、我々は角括弧を交換することができます[ ] , 最も目に見えないASCII演算子の一つで、バックチック.
    これにより、上記範囲チェックを次のように書き換えることができる.
    -- Definition
    a <` b `< c = a < b && b < c
    
    -- Usage
    print (1 <` 2 `< 3) -- true
    print (1 <` 3 `< 2) -- true
    
    したがって、三項演算子を定義するためにこれまでに考えられる最良の仕組みは次のとおりです.
    a X` b `Y c
    
    -- Where a, b and c are the arguments
    -- while X` and `Y together is the name of the ternary operator
    
    優先順位についても、三項演算子は
    例えば、バイナリ演算子よりも優先順位が低い:
    (a <` b + c `< d) MEANS (a <` (b + c) `< d)
    
    関連性については
    左の連想性の上の正しい連想性
    多くの場合、より一般的です.
    したがって:
    a X` b `Y c X` d `Y e = a X` b `Y (c X` d `Y e) 
    
    例えば、条件付き三項演算子
    true then` b `else c = b
    false then` b `else c = c
    
    ここで
    a then` b `else c then` d `else e
    
    通常は(正しい連想)を意味する:
    a then` b `else (c then` d `else e)
    
    (左の連想)
    (a then` b `else c) then` d `else e
    

    結論


    うまくいけば、この記事はあなたにインスピレーションを与えました
    ユーザ定義三項演算子の機構
    読書ありがとう.