这似乎有效,但看起来很笨重。有没有更好的方法来编码呢?
// Hunting for the best index to use for a data compare
let getIndex connDB strTable =
match getIndexByPrimaryKey connDB strTable with
| Some(name) -> Some(name)
| None ->
match getIndexByCluster connDB strTable with
| Some(name) -> Some(name)
| None ->
match getIndexByFirstColumns connDB strTable with
| Some(name) -> Some(name)
| None ->
match getIndexByOnlyUnique connDB strTable with
| Some(name) -> Some(name)
| None ->
match getAnyUniqueIndex connDB strTable with
| Some(name) -> Some(name)
| None -> None
答案 0 :(得分:8)
最简洁的版本可能是使用List.tryPick:
let getIndex connDB strTable =
[ getIndexByPrimaryKey;
getIndexByCluster;
getIndexByFirstColumns;
getIndexByOnlyUnique;
getAnyUniqueIndex; ]
|> List.tryPick (fun fn -> fn connDB strTable)
<强>更新强>
该技术可以很容易地扩展为使用闭包,因此它适用于具有不同参数的函数(还有很多fun
s: - )):
let getIndex connDB strTable =
[ fun () -> getIndexByPrimaryKey connDB strTable;
fun () -> getIndexByCluster connDB strTable;
fun () -> getIndexByFirstColumns connDB strTable;
fun () -> getIndexByOnlyUnique connDB strTable;
fun () -> getAnyUniqueIndex connDB strTable; ]
|> List.tryPick (fun fn -> fn())
答案 1 :(得分:3)
我认为最干净的选择是将getIndexByXYZ
操作定义为活动模式而不是函数。然后你可以编写以下模式匹配:
let getIndex connDB strTable =
match connDB, strTable with
| IndexByPrimaryKey name
| IndexByCluster name
| IndexByFirstColumns name
| IndexByOnlyUnique name
| AnyUniqueIndex name -> Some(name)
如果你仍想在你没有模式匹配的上下文中使用程序其他部分的函数,那么你可以将活动模式定义为简单的包装器:
let (|IndexByPrimaryKey|_|) (connDB, strTable) =
getIndexByPrimaryKey connDB strTable
可悲的是,没有办法“自动”将这些功能转换为活动模式,但我认为如果你需要表达一些业务逻辑并希望它具有可读性,那么额外的努力是值得的。
答案 2 :(得分:1)
我会写一个orElse
函数。然后你可以这样做:
let orElse f = function
| None -> f()
| Some _ as x -> x
let getIndex connDB strTable =
getIndexByPrimaryKey connDB strTable
|> orElse (fun () -> getIndexByCluster connDB strTable)
|> orElse (fun () -> getIndexByFirstColumns connDB strTable)
|> orElse (fun () -> getIndexByOnlyUnique connDB strTable)
|> orElse (fun () -> getAnyUniqueIndex connDB strTable)
或者,如果您更喜欢“工作流程”语法(并经常需要这样),请执行以下操作:
module OrElse =
let bind f = function
| None -> f()
| Some x -> Some x
let combine m1 m2 =
m1 |> bind (fun () -> m2)
type OrElseBuilder() =
member x.Zero() = None
member x.Return(v) = Some v
member x.Bind(m, f) = bind f m
member x.ReturnFrom(m) = m
member x.Combine(m1, m2) = combine m1 m2
member x.Delay(f) = f()
let orElse = OrElseBuilder()
会让你更加坦诚地说明:
open OrElse
orElse {
return! getIndexByPrimaryKey connDB strTable
return! getIndexByCluster connDB strTable
return! getIndexByFirstColumns connDB strTable
return! getIndexByOnlyUnique connDB strTable
return! getAnyUniqueIndex connDB strTable
}
由于您将相同的args传递给每个函数,因此pad的解决方案可能尽可能简洁。这些解决方案解决了替换嵌套match x with Some _ as v -> v | None -> ...
。
扩展Tomas的想法,你可以使用通用的活动模式来“模式化”函数:
let (|FN|_|) f x = f x
然后做:
match connDB, strTable with
| FN getIndexByPrimaryKey name -> Some name
| FN getIndexByCluster name -> Some name
| FN getIndexByFirstColumns name -> Some name
| FN getIndexByOnlyUnique name -> Some name
| args -> getAnyUniqueIndex args
这需要对您的函数稍作修改:args必须是tupled形式。