我想出了两个解决方案来实现我的确切目标。一种是通过使用主动模式:
let orElse(fallback: 'a -> (unit -> 'b) option) (matcher: 'a -> (unit -> 'b) option) (arg: 'a) : (unit -> 'b) option =
let first = matcher(arg)
match first with
| Some(_) -> first
| None -> fallback(arg)
let (|StringCaseHandler|_|)(arg: obj) =
match arg with
| :? string -> Some(fun () -> "string")
| _ -> None
let (|IntCaseHandler|_|)(arg: obj) =
match arg with
| :? int -> Some(fun () -> "integer")
| _ -> None
let (|DefaultCaseHandler|_|)(arg: 'a) =
Some(fun () -> "other")
let msgHandler =
``|StringCaseHandler|_|`` |>
orElse ``|IntCaseHandler|_|`` |>
orElse ``|DefaultCaseHandler|_|``
具有活动模式的解决方案是安全的,因为它不会MatchFailureException
在没有正确匹配的情况下抛出;None
而是返回 a 。
第二个涉及为类型函数定义扩展方法,'a -> 'b
并且尽可能接近 Scala 的“部分函数”orElse
行为,如果结果函数没有产生正确的匹配,则会引发异常:
[<Extension>]
type FunctionExtension() =
[<Extension>]
static member inline OrElse(self:'a -> 'b,fallback: 'a -> 'b) : 'a -> 'b =
fun arg ->
try
self(arg)
with
| :? MatchFailureException -> fallback(arg)
let intMatcher : obj -> string = function
| :? int -> "integer"
let stringMatcher : obj -> string = function
| :? string -> "string"
let defaultMatcher : obj -> string = function
| _ -> "other"
let msgHandler: obj -> string = intMatcher
.OrElse(stringMatcher)
.OrElse(defaultMatcher)