2

I want to simplify expression if(x == 1 || x == 2).
I wish I could write if(x == 1 or 2) but there is no syntax for that.
Other possibility is to use Contains or Any method like: if([1,2].Contains(x)) but this involves unnecessary call.

Can I create some operator which allows me to do this ?

In Nemerle language I can write macro:

macro @|||(left, right)
  match (left)
    | <[ $x == $y ]> => <[ $x == $y || $x == $right ]>
    | _ => Message.Error("Error"); <[ ]>

And then usage:

if (x == 1 ||| 2) { .. }

Can I create operator in such way in F# ?

4

5 に答える 5

9

3文字を保存するためにマクロを作成することはおそらく良い考えではないというブライアンのコメントに同意します。これは、プログラムを読みにくくするだけです(カスタムマクロを知らない人や演算子の意味を変えた人のために)。

さらに、パターンマッチングなどの標準のF#構造を使用して、同じロジックをより簡潔に記述できる可能性が非常に高くなります。例えば:

match x with
| 1 | 2 -> printfn "yes"
| _     -> printfn "no"

慣用的な解決策は具体的なケースに依存しますが、これはあなたが与えた例から判断するのは難しいです。

于 2012-08-27T15:39:07.700 に答える
3

|>haskellモノイドインスタンスの1つの一般的な使用法から借りて、これを達成するために使用できます。

let appendResults f g = (fun x -> f(x) || g(x))
let f x = x=1
let g x = x=2
let inline (>>||) x y = (appendResults f g) x y
let x = 1
if(x |> (1 >>|| 2)) then printfn "true" else printfn "false"

任意の数の引数についてはmconcat、haskellの関連するメソッドを模倣して、同じ効果を得ることができます。おそらく次のようになります。

let rec concatResults = function
| [] -> (fun x -> false)
| (x:xs) -> appendResults x (concatResults xs)

正直なところ、Containsを使用することもできます。それを行う特別なオーバーヘッドがある場合、それが本当に重要であるとは思えません。

于 2012-08-27T13:48:27.097 に答える
2

ブライアンとトーマスに同意します。数回しか使用されない独自のマクロを作成することは、少し実用的な意味があります。
しかし、関数型言語の内部を研究するという点では非常に興味深いと思います。
このことを考慮:

// Generic
let inline mOp1<'a> op sample x = op sample x, sample
let inline mOp2<'a> op1 op2 (b, sample) x = op1 b (op2 sample x), sample

// Implementation for (=) and (||)
let (==) = mOp1 (=)
let (|=) = mOp2 (||) (=)

// Use
let ret1 = x == 1 |= 2 |> fst

詳細、その他の演算子、およびパフォーマンス測定については、https ://stackoverflow.com/a/11552429/974789 を参照してください。

于 2012-08-28T06:28:58.410 に答える
0

これは少しハックですが、機能します

let x = 1
let inline (|||) a b = [a;b]
let inline (==) a b = b |> List.exists (fun t -> t=a)

if x == (1 ||| 2) then printfn "true" else printfn "false"

orとequalsの両方にカスタム演算子が必要です。任意またはチェーンをサポートするためにこれを変更することは難しくありません

もちろん、2つの数字だけが必要な場合は、

let x = 1
let inline (|||) a b = (a,b)
let inline (==) a (c,d) = a=c ||a=d

if x == (1 ||| 2) then printfn "true" else printfn "false"
于 2012-08-27T10:54:36.880 に答える
0

これは、タプルを配列に変換することで機能するため、最高のパフォーマンスを期待しないでください。

let inline (==) a b = 
    Microsoft.FSharp.Reflection.FSharpValue.GetTupleFields(b) 
        |> Array.exists((=) a)

例:

3 == (1,2)      // false
3 == (1,2,3)    // true
于 2012-08-27T11:22:04.747 に答える