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.
我想要简化表达式(x == 1 || x == 2),我希望我可以写if(x == 1或2),但没有语法。另一种可能性是使用包含或任何方法,如:if([1,2].Contains(x)),但这涉及不必要的调用。
Can I create some operator which allows me to do this ?
我可以创建一个操作符让我这样做吗?
In Nemerle language I can write macro:
在Nemerle语言中,我可以写宏:
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# ?
我能在f#中以这种方式创建操作符吗?
5 个解决方案
#1
3
You could use |>
to accomplish this, borrowing from a common use of one of the haskell monoid instances.
您可以使用|>来完成这个任务,从一个haskell monoid实例的常用应用中借用。
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"
For arbitrary numbers of arguments, just mimic the relevant mconcat
method from haskell for the same effect, perhaps like this:
对于任意数量的参数,只需模仿haskell的相关mconcat方法的相同效果,可能如下所示:
let rec concatResults = function
| [] -> (fun x -> false)
| (x:xs) -> appendResults x (concatResults xs)
Honestly though, you may as well just use Contains. If there is any special overhead doing that I doubt it really matters.
老实说,你也可以只使用包含。如果有什么特别的开销,我怀疑这真的很重要。
#2
9
I agree with Brian's comment that constructing a macro in order to save three characters is probably not a good idea. This will only make the program harder to read (for those who do not know your custom macros or changed meaning of operators).
我同意Brian的评论,构建一个宏来保存三个字符可能不是一个好主意。这只会使程序更难以阅读(对于那些不了解您的自定义宏或更改操作符含义的人)。
Moreover, it is quite likely that you could write the same logic in a more concise way using standard F# constructs like pattern matching. For example:
而且,很有可能您可以使用标准的f#结构(如模式匹配)以更简洁的方式编写相同的逻辑。例如:
match x with
| 1 | 2 -> printfn "yes"
| _ -> printfn "no"
The idiomatic solution will depend on the concrete case, which is hard to judge from the example you gave.
惯用的解决方案将取决于具体的案例,这很难从你给出的例子中判断出来。
#3
2
I agree with Brian and Tomas; it makes a little practical sense to invent your own macros that might be used just a few times.
However, I do find it very interesting from the point of studying the internals of functional languages.
Consider this:
我同意布莱恩和托马斯的观点;发明可以使用几次的宏是有点实际意义的。然而,从研究函数式语言的内部结构的角度来看,我发现它非常有趣。考虑一下:
// 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
You may find more details, other operators, and performance measurement here: https://*.com/a/11552429/974789
您可以在这里找到更多的细节、其他操作符和性能度量:https://*.com/a/11552429/974789。
#4
0
This is slightly hackish, but it does work
这有点乱,但确实有效。
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"
It requires a custom operator for both or and equals. It would not be hard to modify this to support arbitrary or chains
它需要一个自定义操作符,既可以也可以等于。要修改它以支持任意或链,并不难。
Of course if you only need 2 numbers you can do
当然,如果你只需要两个数字你就能做到。
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"
#5
0
This works by converting a tupple to an array, so do not expect the best performance.
这是通过将一个tupple转换成一个数组来实现的,所以不要期望最好的性能。
let inline (==) a b =
Microsoft.FSharp.Reflection.FSharpValue.GetTupleFields(b)
|> Array.exists((=) a)
Example:
例子:
3 == (1,2) // false
3 == (1,2,3) // true
#1
3
You could use |>
to accomplish this, borrowing from a common use of one of the haskell monoid instances.
您可以使用|>来完成这个任务,从一个haskell monoid实例的常用应用中借用。
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"
For arbitrary numbers of arguments, just mimic the relevant mconcat
method from haskell for the same effect, perhaps like this:
对于任意数量的参数,只需模仿haskell的相关mconcat方法的相同效果,可能如下所示:
let rec concatResults = function
| [] -> (fun x -> false)
| (x:xs) -> appendResults x (concatResults xs)
Honestly though, you may as well just use Contains. If there is any special overhead doing that I doubt it really matters.
老实说,你也可以只使用包含。如果有什么特别的开销,我怀疑这真的很重要。
#2
9
I agree with Brian's comment that constructing a macro in order to save three characters is probably not a good idea. This will only make the program harder to read (for those who do not know your custom macros or changed meaning of operators).
我同意Brian的评论,构建一个宏来保存三个字符可能不是一个好主意。这只会使程序更难以阅读(对于那些不了解您的自定义宏或更改操作符含义的人)。
Moreover, it is quite likely that you could write the same logic in a more concise way using standard F# constructs like pattern matching. For example:
而且,很有可能您可以使用标准的f#结构(如模式匹配)以更简洁的方式编写相同的逻辑。例如:
match x with
| 1 | 2 -> printfn "yes"
| _ -> printfn "no"
The idiomatic solution will depend on the concrete case, which is hard to judge from the example you gave.
惯用的解决方案将取决于具体的案例,这很难从你给出的例子中判断出来。
#3
2
I agree with Brian and Tomas; it makes a little practical sense to invent your own macros that might be used just a few times.
However, I do find it very interesting from the point of studying the internals of functional languages.
Consider this:
我同意布莱恩和托马斯的观点;发明可以使用几次的宏是有点实际意义的。然而,从研究函数式语言的内部结构的角度来看,我发现它非常有趣。考虑一下:
// 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
You may find more details, other operators, and performance measurement here: https://*.com/a/11552429/974789
您可以在这里找到更多的细节、其他操作符和性能度量:https://*.com/a/11552429/974789。
#4
0
This is slightly hackish, but it does work
这有点乱,但确实有效。
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"
It requires a custom operator for both or and equals. It would not be hard to modify this to support arbitrary or chains
它需要一个自定义操作符,既可以也可以等于。要修改它以支持任意或链,并不难。
Of course if you only need 2 numbers you can do
当然,如果你只需要两个数字你就能做到。
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"
#5
0
This works by converting a tupple to an array, so do not expect the best performance.
这是通过将一个tupple转换成一个数组来实现的,所以不要期望最好的性能。
let inline (==) a b =
Microsoft.FSharp.Reflection.FSharpValue.GetTupleFields(b)
|> Array.exists((=) a)
Example:
例子:
3 == (1,2) // false
3 == (1,2,3) // true