如何将复杂表达式传递给参数化的活动模式?

LOS*_*OST 2 f# active-pattern

我将活动模式"Expression"定义如下:

let (|Expression|_|) expression _ = Some(expression)
Run Code Online (Sandbox Code Playgroud)

现在我试图以这种方式使用它:

match () with
| Expression((totalWidth - wLeft - wRight) / (float model.Columns.Count - 0.5)) cw
    when cw <= wLeft * 4. && cw <= wRight * 4. ->
        cw
| Expression((totalWidth - wLeft) / (float model.Columns.Count - .25)) cw
    when cw <= wLeft * 4. && cw > wRight * 4. ->
        cw
| Expression((totalWidth - wRight) / (float model.Columns.Count - .25)) cw
    when cw > wLeft * 4. && cw <= wRight * 4. ->
        cw
| Expression(totalWidth / float model.Columns.Count) cw
    when cw > wLeft * 4. && cw > wRight * 4. ->
        cw
| _ -> System.InvalidProgramException() |> raise
Run Code Online (Sandbox Code Playgroud)

但这导致"错误FS0010:意外符号' - '在模式中".这可以解决吗?

我想做的是清楚地写出以下等式的解决方案:

max(wl - cw*.25,0)+ max(wr - cw*.25)+ cw*columnCount = ActualWidth

其中cw是唯一的变量.

你能建议更好的方法吗?

Tom*_*cek 6

可以用作参数化活动模式的参数的表达式的语言在某些方面受到限制.据我所知,在F#规范并没有说明确,但语法表明它必须能够解析参数表达式pat-param(90页):

pat-param:=
    | const
    | long-ident
    | [ pat-param ; ......; pat-param ]
    | (pat-param,...,pat-param)
    | long-ident pat-param
    | pat-param:type
    | <@ expr @>
    | <@@ expr @@>
    | 空值

所以,我认为你需要以不同的方式编写模式匹配.您可以将表达式转换为match构造的普通参数,并编写如下内容:

match 
  (totalWidth - wLeft - wRight) / (float model.Columns.Count - 0.5),
  (totalWidth - wLeft) / (float model.Columns.Count - .25),
  (totalWidth - wRight) / (float model.Columns.Count - .25)
with
| cw1, _, _ when cw1 <= wLeft * 4. && cw1 <= wRight * 4. -> cw1
| _, cw2, _ when cw2 <= wLeft * 4. && cw2 > wRight * 4. -> cw2
| _, _, cw3 when cw3 > wLeft * 4. && cw3 <= wRight * 4. -> cw3
| _ -> totalWidth / float model.Columns.Count
Run Code Online (Sandbox Code Playgroud)

如果表达式中使用的模式始终相同,您还可以使用活动模式,如:

let (|Calculate|) w p _ =
  (totalWidth - w) / (float model.Columns.Count - p)
Run Code Online (Sandbox Code Playgroud)

...然后写下这样的东西:

let wDif = wLeft - wRight
match () with
| Calculate wDif 0.5 cw -> cw
| Calculate wLeft 0.25 cw -> cw
// .. etc.
Run Code Online (Sandbox Code Playgroud)