F # Pattern Matching: Сопоставление функций / списков подтипов? - PullRequest
5 голосов
/ 17 ноября 2011
let f (O: obj) = 
    match O with
        | :? (obj -> list<obj>) -> "win"
        | :? list<obj> -> "list!"
        | _ -> "fail"

Console.WriteLine(f(fun x -> ["lol"]))
Console.WriteLine(f(["lol"]))

печатает "fail" дважды, как я полагаю, должно, потому что я даю ia функцию obj -> list<String>, которая не является obj -> list<obj>.Есть ли способ заставить их совпадать?Я мог бы вычеркнуть каждый список в list<obj>, прежде чем сделать из него анонимную функцию, или я мог бы выкинуть все в obj, прежде чем поместить его в список.

Любая из этих работ и делает ее совпадающей, но я подумал, что это проблема, которую ковариация / контрвариантность должна была уже решить?Поправь меня, если я ошибаюсь

1 Ответ

7 голосов
/ 17 ноября 2011

К сожалению, вы не можете решить эту проблему с помощью встроенного сопоставления с образцом.

Единственный способ узнать, является ли значение obj некоторой функцией F #, - это использовать F # Reflection и вызвать метод FSharpType.IsFunction для типа. Вы можете проверить случай в вашем примере следующим образом:

open System    
open Microsoft.FSharp.Reflection    

let f (o : obj) =  
  let ty = o.GetType() 
  if FSharpType.IsFunction(ty) then
    let tyFrom, tyTo = FSharpType.GetFunctionElements(ty)
    if tyTo.IsGenericType && tyTo.GetGenericTypeDefinition() = typedefof<list<_>> then
      printfn "win"
    else 
      printfn "wrong function"
  else
    printfn "not a function"

Console.WriteLine(f(fun x -> "lol"))    // wrong function
Console.WriteLine(f(fun x -> ["lol"]))  // win
Console.WriteLine(f(["lol"]))           // not a function

Вы могли бы инкапсулировать поведение в активном шаблоне F #, чтобы сделать синтаксис более приятным (и использовать сопоставление с образцом в типах). Однако другая проблема заключается в том, что это не дает вам функцию, которую вы могли бы использовать для ее динамического вызова. Я не думаю, что для этого есть встроенная библиотечная функция, поэтому вам, вероятно, потребуется использовать .NET отражение для динамического вызова метода Invoke.

РЕДАКТИРОВАТЬ : были похожие вопросы по SO. Общая проблема заключается в том, что вы сопоставляете некоторые (любые) экземпляры определенного универсального типа, поэтому такая же проблема возникает со списками и т. Д. См., Например:

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...