JsonProvider дает мне разные типы, которые я не могу объединить

Я использую Поставщик типа JSON для загрузки созданного мной файла JSON. Минимальный ввод для поставщика типа выглядит так:

{
  "conv1": {
    "weight": {
      "shape": [ 64, 3, 7, 7 ],
      "data": [ 1e-30, -0.01077061053365469 ]
    }
  },
  "bn1": {
    "eps": 1e-05,
    "weight": {
      "shape": [ 64 ],
      "data": [ 1e-30, 0.2651672959327698 ]
    },
    "bias": {
      "shape": [ 64 ],
      "data": [ 1e-30, 0.24643374979496002 ]
    }
  }
}

Хотя обе части weight имеют одинаковую форму и тип, поставщик типа дает мне два разных, но эквивалентных типа:

type Weight =
    inherit IJsonDocument
    new : shape: int [] * data: float [] -> Weight
    member Data : float []
    member JsonValue: JsonValue
    member Shape: int []

а также

type Weight2 =
    inherit IJsonDocument
    new : shape: int [] * data: float [] -> Weight2
    member Data : float []
    member JsonValue: JsonValue
    member Shape: int []

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

Мой первый подход заключался в использовании перегрузки:

type Tensor = {
    Data:single[]
    Shape:int list
} with
    static member Unify1 (w:NN.Weight) = { Data = w.Data |> Array.map single; Shape = w.Shape |> Array.toList }
    static member Unify1 (w:NN.Weight2) = { Data = w.Data |> Array.map single; Shape = w.Shape |> Array.toList }

Error FS0438 Duplicate method. The method Unify1 has the same name and signature as another method in type Tensor once tuples, functions, units of measure and/or provided types are erased.

Затем я попробовал провести ручное тестирование типа вот так:

let unify2 (o:obj) =
    match o with
    | :? NN.Weight as w -> { Data = w.Data |> Array.map single; Shape = w.Shape |> Array.toList }
    | :? NN.Weight2 as w -> { Data = w.Data |> Array.map single; Shape = w.Shape |> Array.toList }
    | _ -> failwith "pattern oops"

Этот вариант не компилируется, потому что

Error FS3062 This type test with a provided type JsonProvider<...>.Weight is not allowed because this provided type will be erased to Runtime.BaseTypes.IJsonDocument at runtime.

Как я могу заставить поставщика типов создавать унифицированный тип? В качестве альтернативы, как мне самому объединить их, чтобы сделать компилятор счастливым?

Как сделать HTTP-запрос в Javascript?
Как сделать HTTP-запрос в Javascript?
В JavaScript вы можете сделать HTTP-запрос, используя объект XMLHttpRequest или более новый API fetch. Вот пример для обоих методов:
2
0
84
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я согласен с тем, что предполагаемый тип не так хорош, как мог бы быть. Поставщик типа XML имеет статический параметр Global, который объединяет элементы XML по всему документу на основе их имени - так что, предположительно, поставщик JSON мог бы сделать что-то подобное (но это более сложно, потому что нам нужно будет определить, что две записи "одинаковы" "на основе либо только их полей, либо метки, используемой в родительском элементе ...). Если вы хотите внести свой вклад в F# Data, пожалуйста, откройте вопрос, чтобы обсудить это!

Между тем, я думаю, что разумным обходным путем является получение базового JsonValue, а затем его упаковка обратно в предоставленный тип Weight. Это будет работать для обеих записей weight, потому что они имеют одинаковые поля:

type NN = JsonProvider<"""{ ... }""">

let processWeight (js:JsonValue) = 
  let w = NN.Weight(js)
  w.Data, w.Shape

let nn = NN.GetSample()
nn.Conv1.Weight.JsonValue |> processWeight
nn.Bn1.Weight.JsonValue |> processWeight

Немного более изящной версией было бы использование статических ограничений членов для доступа к свойству JsonValue в функции processWeight (чтобы вы могли просто вызвать nn.Conv1.Weight |> processWeight), но я не хотел усложнять образец.

Интересно, что я не подумал передать JsonValue правильному конструктору. Спасибо.

primfaktor 13.09.2018 08:17

Другие вопросы по теме