与 OR 和 WHEN 子句匹配的模式
Pattern matching with OR and WHEN clauses
我有问题,模式匹配没有按预期编译
当前的简化版本如下所示
match smth with
| pattern1 when isSomething pattern1 ->
doWork()
| pattern2 when isSomething pattern2 ->
doWork()
| _ -> () // do nothing
这里的问题是在不同的情况下body是重复的
我试过用OR pattern把它改成这个
match smth with
| pattern1 when isSomething pattern1
| pattern2 when isSomething pattern2 ->
doWork()
| _ -> () // do nothing
但它给出了 Unexpected symbol '|' in pattern matching. Expected '->' or other token. F# Compiler 10
尝试用括号包围 isSomething
没有帮助。在那种情况下如何避免重复?
原代码
match state.SearchOptions with
| { Pattern = empty } when String.IsNullOrEmpty empty ->
ValueSome (i, p, state.SelectedConfiguration, state.Solution.Configurations)
| { Pattern = pattern; IsRegex = true; IsCaseSensitive = true } when Regex.isMatch p.Name pattern ->
ValueSome (i, p, state.SelectedConfiguration, state.Solution.Configurations)
| { Pattern = pattern; IsRegex = true; IsCaseSensitive = false } when Regex.isMatchCaseInsensitive p.Name pattern ->
ValueSome (i, p, state.SelectedConfiguration, state.Solution.Configurations)
| { Pattern = pattern; IsRegex = false; IsCaseSensitive = true } when p.Name.Contains(pattern, StringComparison.InvariantCulture) ->
ValueSome (i, p, state.SelectedConfiguration, state.Solution.Configurations)
| { Pattern = pattern; IsRegex = false; IsCaseSensitive = false } when p.Name.Contains(pattern, StringComparison.InvariantCultureIgnoreCase) ->
ValueSome (i, p, state.SelectedConfiguration, state.Solution.Configurations)
| _ -> ValueNone
如评论中所述,这是无法做到的 - when
子句适用于整个子句。我认为有三种替代方法。
首先,您可以将结果值定义为 match
表达式之前的变量,然后仅 return 来自所有四种情况的变量(如评论中所建议)。
其次,您实际上可以将其写成一个普通的 if
表达式:
let so = state.SearchOptions
if String.IsNullOrEmpty so.Pattern then
ValueSome (i, p, state.SelectedConfiguration, state.Solution.Configurations)
elif ( so.IsRegex && so.IsCaseSensitive &&
Regex.isMatch p.Name so.Pattern )
|| ( so.IsRegex && not so.IsCaseSensitive &&
Regex.isMatchCaseInsensitive p.Name so.Pattern )
|| ( not so.IsRegex && so.IsCaseSensitive &&
p.Name.Contains(so.Pattern, StringComparison.InvariantCulture) )
|| ( not so.IsRegex && not so.IsCaseSensitive &&
p.Name.Contains(so.Pattern, StringComparison.InvariantCultureIgnoreCase) ) then
ValueSome (i, p, state.SelectedConfiguration, state.Solution.Configurations)
else ValueNone
另一种选择是使用活动模式 - 这样,您就可以将条件集成到模式本身中。这样的事情应该可以解决问题:
let (|RegexMatch|_|) input pattern =
if Regex.isMatch input pattern then Some() else None
let (|RegexMatchInsensitive|_|) input pattern =
if Regex.isMatchCaseInsensitive input pattern then Some() else None
let (|Contains|_|) (input:string) pattern
input.Contains(pattern, StringComparison.InvariantCulture)
let (|ContainsInsensitive|_|) (input:string) pattern
input.Contains(pattern, StringComparison.InvariantCultureIgnoreCase)
match state.SearchOptions with
| { Pattern = empty } when String.IsNullOrEmpty empty ->
ValueSome (i, p, state.SelectedConfiguration, state.Solution.Configurations)
| { Pattern = Match p.Name; IsRegex = true; IsCaseSensitive = true }
| { Pattern = RegexMatchInsensitive p.Name; IsRegex = true; IsCaseSensitive = false }
| { Pattern = Contains p.Name; IsRegex = false; IsCaseSensitive = true }
| { Pattern = ContainsInsensitive p.Name; IsRegex = false; IsCaseSensitive = false } ->
ValueSome (i, p, state.SelectedConfiguration, state.Solution.Configurations)
| _ -> ValueNone
如果我只在一个地方这样做,我可能会选择选项一或选项二(取决于您觉得哪个更易读)。如果您正在做更多类似的事情,第三个选项是一个不错的选择。
我有问题,模式匹配没有按预期编译
当前的简化版本如下所示
match smth with
| pattern1 when isSomething pattern1 ->
doWork()
| pattern2 when isSomething pattern2 ->
doWork()
| _ -> () // do nothing
这里的问题是在不同的情况下body是重复的
我试过用OR pattern把它改成这个
match smth with
| pattern1 when isSomething pattern1
| pattern2 when isSomething pattern2 ->
doWork()
| _ -> () // do nothing
但它给出了 Unexpected symbol '|' in pattern matching. Expected '->' or other token. F# Compiler 10
尝试用括号包围 isSomething
没有帮助。在那种情况下如何避免重复?
原代码
match state.SearchOptions with
| { Pattern = empty } when String.IsNullOrEmpty empty ->
ValueSome (i, p, state.SelectedConfiguration, state.Solution.Configurations)
| { Pattern = pattern; IsRegex = true; IsCaseSensitive = true } when Regex.isMatch p.Name pattern ->
ValueSome (i, p, state.SelectedConfiguration, state.Solution.Configurations)
| { Pattern = pattern; IsRegex = true; IsCaseSensitive = false } when Regex.isMatchCaseInsensitive p.Name pattern ->
ValueSome (i, p, state.SelectedConfiguration, state.Solution.Configurations)
| { Pattern = pattern; IsRegex = false; IsCaseSensitive = true } when p.Name.Contains(pattern, StringComparison.InvariantCulture) ->
ValueSome (i, p, state.SelectedConfiguration, state.Solution.Configurations)
| { Pattern = pattern; IsRegex = false; IsCaseSensitive = false } when p.Name.Contains(pattern, StringComparison.InvariantCultureIgnoreCase) ->
ValueSome (i, p, state.SelectedConfiguration, state.Solution.Configurations)
| _ -> ValueNone
如评论中所述,这是无法做到的 - when
子句适用于整个子句。我认为有三种替代方法。
首先,您可以将结果值定义为 match
表达式之前的变量,然后仅 return 来自所有四种情况的变量(如评论中所建议)。
其次,您实际上可以将其写成一个普通的 if
表达式:
let so = state.SearchOptions
if String.IsNullOrEmpty so.Pattern then
ValueSome (i, p, state.SelectedConfiguration, state.Solution.Configurations)
elif ( so.IsRegex && so.IsCaseSensitive &&
Regex.isMatch p.Name so.Pattern )
|| ( so.IsRegex && not so.IsCaseSensitive &&
Regex.isMatchCaseInsensitive p.Name so.Pattern )
|| ( not so.IsRegex && so.IsCaseSensitive &&
p.Name.Contains(so.Pattern, StringComparison.InvariantCulture) )
|| ( not so.IsRegex && not so.IsCaseSensitive &&
p.Name.Contains(so.Pattern, StringComparison.InvariantCultureIgnoreCase) ) then
ValueSome (i, p, state.SelectedConfiguration, state.Solution.Configurations)
else ValueNone
另一种选择是使用活动模式 - 这样,您就可以将条件集成到模式本身中。这样的事情应该可以解决问题:
let (|RegexMatch|_|) input pattern =
if Regex.isMatch input pattern then Some() else None
let (|RegexMatchInsensitive|_|) input pattern =
if Regex.isMatchCaseInsensitive input pattern then Some() else None
let (|Contains|_|) (input:string) pattern
input.Contains(pattern, StringComparison.InvariantCulture)
let (|ContainsInsensitive|_|) (input:string) pattern
input.Contains(pattern, StringComparison.InvariantCultureIgnoreCase)
match state.SearchOptions with
| { Pattern = empty } when String.IsNullOrEmpty empty ->
ValueSome (i, p, state.SelectedConfiguration, state.Solution.Configurations)
| { Pattern = Match p.Name; IsRegex = true; IsCaseSensitive = true }
| { Pattern = RegexMatchInsensitive p.Name; IsRegex = true; IsCaseSensitive = false }
| { Pattern = Contains p.Name; IsRegex = false; IsCaseSensitive = true }
| { Pattern = ContainsInsensitive p.Name; IsRegex = false; IsCaseSensitive = false } ->
ValueSome (i, p, state.SelectedConfiguration, state.Solution.Configurations)
| _ -> ValueNone
如果我只在一个地方这样做,我可能会选择选项一或选项二(取决于您觉得哪个更易读)。如果您正在做更多类似的事情,第三个选项是一个不错的选择。