Как передать сложное выражение параметризованному активному шаблону? - PullRequest
2 голосов
/ 29 мая 2011

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

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 Ответ

6 голосов
/ 29 мая 2011

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

pat-param: =
| сопз
| давно идент
| [ pat-param ; ...; пат-парам ]
| ( pat-param , ..., pat-param )
| длинный идентификатор pat-param
| pat-param : type
| <@ <em>expr @>
| <@@ <em>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.
...