Как я могу передать сложное выражение параметризованному активному образцу?

Я определил активный шаблон "Выражение" следующим образом:

let (|Expression|_|) expression _ = Some(expression)

Сейчас я пытаюсь использовать это таким образом:

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

Но это приводит к "ошибке FS0010: неожиданный символ" - "в шаблоне". Это поправимо?

Что я пытаюсь сделать, это написать четко решение следующего уравнения:

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

где cw - единственная переменная.

Можете ли вы предложить лучший способ?

1 ответ

Решение

Язык выражений, которые можно использовать в качестве аргументов для параметризованных активных шаблонов, в некоторых отношениях ограничен. Насколько я могу судить, спецификация F# не говорит этого явно, но грамматика предполагает, что должна быть возможность проанализировать выражение аргумента как pat-param (страница 90):

пат-парам: =
| Const
| давно идент
| [ пат-парам; ...; пат-парам ]
| (пат-парам, ..., пат-парам)
| длинный пат-парам
| пат-парам: тип
| <@ 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

Если шаблон, используемый в выражении, всегда один и тот же, вы также можете использовать активный шаблон, например:

let (|Calculate|) w p _ =
  (totalWidth - w) / (float model.Columns.Count - p)

... а затем напишите что-то вроде:

let wDif = wLeft - wRight
match () with
| Calculate wDif 0.5 cw -> cw
| Calculate wLeft 0.25 cw -> cw
// .. etc.
Другие вопросы по тегам