2015-11-12 3 views
2

я это dicriminated союз, который представляет собой примитивный тип:Как преобразовать список объектов в примитивный тип данных?

type Expr = 
    | Int of bigint 
    | Real of float 
    | Symbol of string 
    | Bool of bool 
    | List of Expr list 

И я пишу функцию list : obj list -> Expr list, которая будет проверять для типов объектов и преобразует их в Expr «s соответственно:

let rec list : (obj list -> Expr list) = function 
    | head::tail -> 
     match head with 
     | :? string as x'-> Symbol (x') :: list tail 
     | :? int as x'-> Int(bigint x') :: list tail 
     | :? bigint as x' -> Int x' :: list tail 
     | :? bool as x' -> Bool x' :: list tail 
     | :? float as x' -> Real x' :: list tail 
     | :? Expr as x' -> x' :: list tail 
     | :? list<obj> as x' -> List(list x') :: list tail 
    | _ -> [] 

Случай | :? list<obj> as x' -> List(list x') :: list tail, кажется, не соответствует при вызове этой функции во вложенном списке следующим образом: list [1;[2;1]] это компилируется отлично, но возвращает ошибку, говоря, что случаи совпадения не были полными, кажется, что он пытается mach list<int> с случаями, и он не находит его. Я ожидал, что list<obj> будет соответствовать спискам любого типа 'a, но это не так. Какую модель следует писать, чтобы она соответствовала списку любого типа? Функция отлично работает для не вложенных списков объектов.

+1

Я думаю, вы должны задумайтесь над тем, почему вы хотите/должны это сделать - я обычно стараюсь не использовать этот тип времени выполнения проверка – Carsten

+0

@Carsten Я пишу DSL для взаимодействия с Mathematica, это позволяет передавать список различных типов и вложенных списков в функцию Mathematica. Так, например, 'Таблица [Power [n; 2]; [П; 1; 10]] 'будет легальным синтаксисом в F # –

+0

См. Http://stackoverflow.com/questions/8169233/f-pattern-matching-matching-functions-lists-of-subtypes и http://stackoverflow.com/questions/ 2140079/как к отливка-объект к-а-список-оф-родового типа-в-ф. – kvb

ответ

2

Соответствие шаблону является неполным, поскольку head имеет тип obj. Случаи, не покрытые, например, nullobj(), 1L (64-разрядное целое число), System.Version(), System.Guid("DAB51019-DF69-4547-BC3B-5CE06BE22A7B"), [| 1; 2 |] и т.д.

Есть неограниченное число случаев не обрабатываются, потому что obj означает что-нибудь, в том числе пользовательских типы.

Какую модель следует писать, чтобы она соответствовала списку любого типа?

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

+0

Спасибо за ответ, я попробовал использовать шаблон подстановки, я могу использовать отражение, чтобы проверить, что 'x' действительно является списком (или массивом, или seq ... и т. Д.). но с этой точки у меня есть «x: obj», и я не знаю, как это сделать для «obj list» (так что я могу передать его снова в «list») –

+0

@ZaidAjaj вы не можете использовать 'int list 'в' obj list'. Наследования нет.Вы можете создать экземпляр списка как 'obj list', поместив в него цепочки. Вместо '[2; 1] 'вы бы набрали' [box 2; box 1] '. – phoog

4

Невозможно использовать сопоставление образцов, чтобы проверить, что объект является значением родового типа с неопределенными аргументами общего назначения. Вы можете проверить, является ли это list<int> или list<obj>, но это должен быть именно этот тип - так что list<int> не будет сопоставлен при проверке типа с помощью :? list<obj> (также вы можете написать :? list<_>, но компилятор просто заполнит _ с obj)

Если вы заботитесь только о коллекциях, вы можете однако использовать необщие System.Collections.IEnumerable интерфейс, который все коллекции (списки, массивы и т.д.) реализацию:

let rec list : (obj list -> Expr list) = function 
    | head::tail -> 
     match head with 
     | :? string as x'-> Symbol (x') :: list tail 
     // Other cases you're already covering 
     | :? float as x' -> Real x' :: list tail 
     | :? Expr as x' -> x' :: list tail 
     | :? System.Collections.IEnumerable as x' -> 
      // It is a collection and we can get its elements as `obj` values! 
      let nested = x' |> Seq.cast |> List.ofSeq |> list 
      List(nested) :: list tail 
    | _ -> [] 
+0

Однако вы можете написать активный шаблон, который будет сравнивать определения общего типа (с использованием typedefof с одной стороны и GetGenericTypeDefinition - с другой). – scrwtp

Смежные вопросы