如何在函数表达式中编写 F# 活动模式匹配函数?

4
我们有这些小的辅助函数。
open System

let (|NonEmptyString|) value =
    if String.IsNullOrEmpty value
    then failwith "String must be non-empty."
    else value

let (|StartsWithX|) (value:string) =
    if value.StartsWith("X") |> not
    then failwith "String must start with X."
    else value

在函数接口中使用非空字符串的活动模式匹配函数是有效的:

let hi (NonEmptyString s) = printfn "Hi %s" s

hi "X"  // Hi X
hi ""   // System.Exception: String must be non-empty.

现在来看问题。
将一些验证器组合成更复杂的验证约束会很好,像这样:
let hi (NonEmptyString s  &  StartsWithX s) = printfn "Hi %s" s
// error FS0038: 's' is bound twice in this pattern

如果只允许使用一个“s”,我们可以考虑将函数合并,这样我们只有一个参数s。由于活动模式匹配函数本质上也是函数,因此应用函数组合运算符>>,但在这里不适用。
let hi (NonEmptyString >> StartsWithX s) = printfn "Hi %s" s
// error FS0010: Unexpected infix operator in pattern

那么问题是,我们如何在 F# 4.0 中实现呢?


任何方法都会有一些小技巧。为什么不在等号的另一侧进行检查呢? - John Palmer
2
只需使用通配符:let hi (NonEmptyString s & StartsWithX _) = printfn "Hi %s" s。但是,你现在的做法看起来不太像F#的典型写法。 - kvb
@kvb 啊哈,类型推断将为通配符找到s。 我只是在尝试。 要以 F#的惯用方式执行此操作,我将使用单个 case ADT 作为类型。 但是我在这里进行合成实验。 谢谢,我赞了你的评论。 - Functional_S
1
@Functional_S - 由于这些模式只是将输入不加修改地返回作为输出,因此您也可以直接组合这些模式:let hi (NonEmptyString (StartsWithX s)) = ...。但这种方法无法推广到更习惯用法的活动模式。 - kvb
@kvb,什么是惯用的方式来做这件事? - ca9163d9
显示剩余3条评论
1个回答

1
作为@kvb的评论所说,通配符_在AND情况下有帮助。
// AND
let hi (NonEmptyString _  &  StartsWithX s) = printfn "Hi %s" s

OR情况适用于两个's'绑定

// OR
let hi (NonEmptyString s  |  StartsWithX s) = printfn "Hi %s" s
// The logic here makes less sense. It's kept simple with the given helper functions from above.  

注意:
这只是为了在函数接口中以代码合同的形式描述活动模式匹配组合而进行的实验。
这可以被视为使用或滥用活动模式匹配(符合F#语言习惯或不符合),这取决于你的选择!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接