F#元编程:是否可以使IF X = 1或2语法?

时间:2012-08-27 10:12:02

标签: f# programming-languages metaprogramming nemerle

我想简化表达式if(x == 1 || x == 2) 我希望我能写if(x == 1 or 2),但没有任何语法。
其他可能性是使用Contains或Any方法,例如:if([1,2].Contains(x))但这涉及不必要的调用。

我可以创建一些允许我这样做的运算符吗?

在Nemerle语言中我可以写宏:

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

然后用法:

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

我可以在F#中以这种方式创建运算符吗?

5 个答案:

答案 0 :(得分:9)

我同意Brian的意见,即为了保存三个字符而构建一个宏可能不是一个好主意。这只会使程序更难阅读(对于那些不了解自定义宏或改变运算符含义的人来说)。

此外,您很可能使用标准F#构造(如模式匹配)以更简洁的方式编写相同的逻辑。例如:

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

惯用解决方案将取决于具体情况,这很难从你给出的例子来判断。

答案 1 :(得分:3)

您可以使用|>来完成此操作,借用其中一个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"

对于任意数量的参数,只需模仿haskell中相关的mconcat方法获得相同的效果,也许是这样的:

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

老实说,你也可以使用Contains。如果有任何特殊的开销,我怀疑它真的很重要。

答案 2 :(得分:2)

我同意Brian和Tomas;它有点实用感觉来发明你自己的宏,可能只使用了几次 但是,从研究函数式语言的内部结构来看,我非常有趣 考虑一下:

// 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

答案 3 :(得分:0)

这有点hackish,但确实有效

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"

它需要两个或等于的自定义运算符。修改它以支持任意或链

并不难

当然如果你只需要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"

答案 4 :(得分:0)

这可以通过将元组转换为数组来实现,因此不要期望最佳性能。

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

示例:

3 == (1,2)      // false
3 == (1,2,3)    // true