Что не так с сопоставлением ActivePattern с System.Type? - PullRequest
0 голосов
/ 24 августа 2018
module Reflection = 
    [<RequireQualifiedAccess>]
    module Type = 
        let isType<'a> = Unchecked.defaultof<'a>
        let (|IsEqual|Isnt|) (_:'a) (t:Type):Choice<unit,unit> =
            let t' = typeof<'a>
            if t = t' then IsEqual else Isnt
        let (|TypeOf|_|) (_:'a) (t:Type) :unit option =
            if t = typeof<'a> then Some ()
            else
                //printfn "did not match %A to %A" typeof<'a> t
                None

open Reflection

match typeof<string> with
// compiles just fine
| Type.TypeOf (Type.isType:int) as x -> Some x.Name
// does not compile
| Type.IsEqual (Type.isType:string) as x -> Some x.Name
| _ -> None

т Type mismatch. Expecting a Type -> Choice<'a,'b> but given a Type -> 'c -> Choice<unit,unit> The type 'Choice<'a,'b>' does not match the type ''c -> Choice<unit,unit>' (using external F# compiler)

Ответы [ 2 ]

0 голосов
/ 27 августа 2018

Чтобы добавить к ответу Федора, спецификация очень четко указывает на действительные формы активных шаблонов (больше, чем MSDN по крайней мере) - см. Параграф 7.2.3 «Активные шаблоны».

Пять допустимых форм:

  • Одиночный регистр - (|CaseName|) inp
  • Частично - (|CaseName|_|) inp
  • Мульти-регистр - (|CaseName1|...|CaseNameN|) inp
  • Отдельный регистр с параметрами - (|CaseName|) arg1 ... argn inp
  • Частично с параметрами - (|CaseName|_|) arg1 ... argn inp

Другие активные функции шаблона не разрешены.

Что здесь наиболее важно, нет способа объединить шаблон с несколькими случаями с дополнительными параметрами.

0 голосов
/ 24 августа 2018

По какой-то причине подобные шаблоны просто запрещены.Только шаблоны с ровно одним результатом могут принимать дополнительные параметры.

Это допустимо:

let (|A|) x y = if x = y then 5 else 42

let f (A "foo" a) = printfn "%A" y
f "foo"  // Prints "5"
f "bar"  // Prints "42"

И это разрешено:

let (|B|_|) x y = if x = y then Some (y+5) else None

let f = function 
    | B 42 x -> printfn "%d" x 
    | _ -> printfn "try again"

f 42  // prints "47"
f 5   // prints "try again"

Но это все.Все остальные активные шаблоны должны быть без параметров.И то, и другое незаконно:

let (|A|B|) x y = ...
let (|A|B|_|) x y = ...

Если бы мне пришлось размышлять, я бы сказал, что это связано с предсказуемой производительностью во время выполнения.Когда шаблон либо совпадает, либо нет, компилятор может запустить его ровно один раз для каждого значения параметра.Но если шаблон возвращает несколько вещей, и некоторые из этих вещей присутствуют в выражении соответствия, а другие - нет, и не все из них имеют один и тот же параметр - становится очень сложно найти лучший способ сделать минимумколичество вызовов функций.

...