Thoth.Json.Net - Декодер как функтор, возможно ли это?

Я нашел эту превосходную библиотеку JSON для F#, она вдохновлена ​​Json.Decode от Elm и определяет базовый Decoder введите вот так:

type Decoder<'T> = string -> obj -> Result<'T, DecoderError> (Вот)

Есть такие функции, как Decode.map, и я хотел бы сделать его совместимым с F#+, чтобы я мог использовать его так:

let customerId = Decode.string |>> CustomerId(см. |>> инфиксная версия общей карты)

Насколько я понимаю, чтобы сторонняя библиотека использовала концепции F#+, такие как Functors, необходимо расширить сторонний тип с помощью static member Map, но Decoder<'T> это просто сокращение.

Есть какое-нибудь решение? Кто-нибудь пробовал?

PS Мое решение пока настраиваемая привязка:

let (<!>) = Decode.map
let customerId: Decoder<CustomerId> = CustomerId <!> Decode.string
let submitId: Decoder<SubmitId> = SubmitId <!> Decode.string
let currency: Decoder<Currency> = Currency <!> Decode.string
// etc…

1 ответ

Решение

Проблема в том, что вы не контролируете код. Если бы у вас был контроль над этим, решение было бы:

  • Воплощать в жизнь Decoderкак конкретный тип, а не как псевдоним типа. Псевдоним типа не может иметь дополнительных членов, потому что на самом деле это не другой тип. Авторам библиотек следует использовать объединения с распознаванием одного регистра, поскольку теперь вы можете создавать их структуры с почти нулевыми накладными расходами.

  • Добавить участника Map с необходимой подписью.

В качестве альтернативы, если члены расширений станут видимыми для ограничений признаков в будущей версии F#, вы сможете просто расширить тип с помощью функции Map, возможно, с некоторыми нежелательными эффектами, поскольку это псевдоним типа для функции с двумя аргументами.

Итак, я думаю, лучшее, что вы можете сделать, это то, что вы уже показали.

В качестве побочного примечания вам может быть интересно взглянуть на Fleece, который также предоставляет декодеры, но он также идет еще на один шаг и предоставляет вам кодеки, которые работают в обоих направлениях (и вы можете map и <*> над ним).

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