Как я могу передать сложное выражение параметризованному активному образцу?
Я определил активный шаблон "Выражение" следующим образом:
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.