Подтвердить что ты не робот

Расширение существующего типа в OCaml

В последнее время я занимаюсь программированием OCaml, чтобы изучить язык и познакомиться с функциональным программированием. В последнее время я начал думать, что хочу расширить существующий тип (либо встроенный, либо один из моих собственных), например:

type bexp =
  And of bexp * bexp
| Or of bexp * bexp
| Xor of bexp * bexp
| Not of bexp;;

Теперь скажем, я хочу добавить вариант Nop к этому типу, но только для использования в новом типе - вроде подобного наследования. Эй, они должны быть алгебраическими типами данных, верно? Так почему бы не что-то вроде:

type nbexp = bexp | Nop nbexp ;;

... но это недействительно OCaml, оно дает синтаксическую ошибку. В основном то, что я пытаюсь сделать, это сказать, что я хочу, чтобы nbexp включал все, что включает bexp, а также добавляет Nop к этому. Я предполагаю, что это невозможно, потому что, если вы, например, использовали конструктор And, не могли бы определить, был ли он bexp-типом или типом nbexp. (Я думаю, что конструктор Nop, принимающий nbexp, также может быть проблематичным.)

Итак, есть ли способ сделать что-то подобное в OCaml? И, это что-то, что можно сделать в Haskell (возможно, с помощью моделей)?

4b9b3361

Ответ 1

Интересным решением является использование полиморфного варианта:

type bexp =
[ `And of bexp * bexp
| `Or of bexp * bexp
| `Xor of bexp * bexp
| `Not of bexp ];;

type nbexp = [ bexp | `Nop of nbexp ];;

Обратите внимание, что полиморфные варианты сложнее обычных, но позволяют расширять тип.

Интересный пример оценки выражения с расширением с использованием полиморфного варианта можно найти в тестовых каталогах источника ocaml, см. svn

Ответ 2

Эй, они должны быть алгебраическими типами данных, правильно?

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

Типированная схема поддерживает не тегированные союзы, поэтому вы можете проверить ее.

Ответ 3

Как вы сами правильно догадались, это невозможно в алгебраических типах. Я согласен с предложением Apocalisp, что вы можете просто обернуть "унаследованную" часть nbexp в свой конструктор.

Я бы добавил, что отсутствие наследования алгебраических типов является частью их чудесности. Это означает, что выражение, такое как And(foo, bar), однозначно типизировано, и что кастинг (вверх или вниз) не играет никакой роли в системе типов. Это дает как большую безопасность, так и большую ясность. Разумеется, требуется программист, чтобы он/она явно обрабатывал случаи, когда он/она хочет взаимодействовать с bexp частями nbexp, но если вы думаете об этом, то, как реализуется повышенная безопасность и ясность на практике.