Нет конструктора типов для типов записей? - PullRequest
7 голосов
/ 29 декабря 2011

Я переводил следующий код на Haskell в OCaml:

data NFA q s = NFA
{ intialState :: q
, isAccepting :: q -> Bool
, transition  :: q -> s -> [q]
}

Сначала я попробовал очень буквальный перевод:

type ('q,'s) nfa = NFA of { initialState: 'q;
                            isAccepting:  'q -> bool;
                            transition:   'q -> 's -> 'q list }

... и, конечно, это дает синтаксическую ошибкупотому что часть конструктора типа, "NFA of" не допускается.Это должно быть:

 type ('q,'s) nfa = { initialState: 'q;
                      isAccepting:  'q -> bool;
                      transition:   'q -> 's -> 'q list }

Это заставило меня задуматься, почему это так.Почему вы не можете иметь конструктор типа для типа записи так же, как и для типа кортежа (как показано ниже)?

type ('q, 's) dfa = NFA of ('q * ('q->bool) * ( 'q -> 's -> 'q list) )

Ответы [ 2 ]

16 голосов
/ 29 декабря 2011

Зачем вам хотеть конструктор типов для типов записей, за исключением того, что вы привыкли в Haskell?

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

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

Почему у вас не может быть конструктора типа для типа записикак вы могли бы для типа кортежа (как показано ниже)?

Будьте осторожны!В показанном примере нет кортежа, только тип суммы с несколькими параметрами.Foo of bar * baz - это , а не - это то же самое, что и Foo of (bar * baz): первый конструктор имеет два параметра, а последний конструктор имеет только один параметр, который является кортежем.Это разграничение выполняется по соображениям производительности (в памяти два параметра упаковываются вместе с тегом конструктора, а кортеж создает указатель косвенности).Использование кортежей вместо мультипараметров немного более гибко: вы можете сопоставить как Foo (x, y) -> ... или Foo p -> ..., последний не доступен для многопараметрических конструкторов.

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

type foo =
  | Foo of { x : int; y : int }
  | Bar of { z : foo list }

вместо текущего

type foo = Foo of foo_t | Bar of bar_t
and foo_t = { x : int; y : int }
and bar_t = { z : foo list }

Ваш запрос является частным (и не очень интересным) случаем этого вопроса.Однако даже при таком сокращенном синтаксисе между конструктором и данными все равно будет один указатель косвенности, что делает этот стиль непривлекательным для программ, ориентированных на производительность, - может пригодиться возможность иметь по имени конструкторпараметры.

PS: Я не говорю, что выбор Haskell для десагерирования записей в кортежи - это плохо.Переводя одну функцию в другую, вы уменьшаете избыточность / дублирование концепций.Тем не менее, я лично думаю, что было бы более естественно десугаровать кортежи в записи (с числовыми именами полей, как это сделано, например, в Oz).В дизайне языка программирования часто нет «хороших» и «плохих» вариантов, только разные компромиссы.

2 голосов
/ 29 декабря 2011

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

Обратите внимание, что имена меток записей привязаны к определенному типу, например, {initialState=q} - это шаблон типа ('q, 's) nfa; Вы не можете использовать название метки в другом типе. Таким образом, именование конструктора действительно полезно, только когда тип имеет несколько конструкторов; затем, если у вас много аргументов в конструкторе, вы можете определить отдельный тип аргументов.

Я полагаю, что есть патч для этой функции, но я не знаю, является ли он актуальным для последней версии OCaml или чего-то еще, и для этого потребуется кто-нибудь, использующий ваш код.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...