Как мне написать универсальную функцию для обработки нескольких типов записей в ReScript?

Учитывая следующий надуманный пример, можно ли написать get функция, которая может обрабатывать любую запись с a свойство?

      type type_one = {a: int}
type type_two = {a: int, b: int}

let example_one = {a: 1}
let example_two = {a: 1, b: 2}

let get = record => record.a

Js.log(get(example_one)) // notice the error here
Js.log(get(example_two))

Игровая площадка ReScript

Если нет, возможно ли это с объектом? Или как лучше всего справиться с этой ситуацией?

1 ответ

Решение

Это не. Поскольку записи являются номинальными (в отличие от структурно) типизированными, невозможно указать «любую запись с полем». Следовательно get будет выведен последний тип, который компилятор видел с a поле, которое type_two.

Однако существует тип объекта, который является структурным с подтипами, что позволяет это:

      type type_one = {"a": int}
type type_two = {"a": int, "b": int}

let example_one = {"a": 1}
let example_two = {"a": 1, "b": 2}

let get = (record) => record["a"]


Js.log(get(example_one)) // notice no error here
Js.log(get(example_two))

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

Также, в качестве примечания, на некоторых языках это может быть выполнено другим способом - с помощью специального полиморфизма, путем явного определения общего интерфейса и реализаций, прикрепленных к определенным типам (называемых классами типов в Haskell, чертами в Rust). Rescript и OCaml, к сожалению, в настоящее время также не поддерживают это, хотя есть предложение для OCaml в виде модульных имплицитов. Однако в OCaml вы по-прежнему можете определять общий интерфейс и реализации с помощью модулей и передавать их явно . Rescript также поддерживает типы модулей и модули, но, к сожалению, он, похоже, не раскрывает первоклассные модули, то есть передает модули как значения. Так что это тоже похоже на запрет.

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