Еще один новый тип против данных (стилистическая проблема) - PullRequest
8 голосов
/ 15 февраля 2012

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

  1. Использовать только data.Это нормально, за исключением того, что у меня есть много типов только с одним конструктором с одним аргументом.Код выглядит каким-то расточительным ... Хотя мне все равно, какое повышение производительности, но он не выглядит правильным.
  2. Используйте только newtype.Это приводит к большим уродствам с кортежами в случае нескольких параметров.
  3. Mix data и newtype, которые несколько выглядят неоднородно и слегка раздражают. Я бы предпочел, чтобы все типы были объявлены вединый последовательный путь.

Я нахожусь в дилемме выбора между 1 и 3.

Ответы [ 2 ]

11 голосов
/ 15 февраля 2012

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

Во-вторых, и самое главное, newtype имеет различная семантика до data!Конструктор newtype является строгим, в отличие от конструкторов data, которые не являются строгими, если вы явно не используете строгие поля.Даже если вы не заботитесь о строгости, или все поля ваших data являются строгими, все же есть некоторые тонкие различия .

Я не думаю, что один конструктортипы с одним аргументом data являются бесполезными - синтаксически, они такие же легкие, как newtype, и семантически кажутся мне более важными.

Вы сказали, что не беспокоитесь о производительности,но если накладные расходы во время выполнения для data были действительно неудобными, то вы можете смешивать их, если вы знаете о семантических различиях.Однако, если вы используете -funbox-strict-fields, то GHC может оптимизировать для вас одиночный конструктор с одним аргументом data s, если они встречаются как строгие поля в других типах данных.

Обычновы должны использовать newtype при переносе существующего типа в целях безопасности / абстракции во время компиляции или для определения ваших собственных экземпляров, и использовать data всякий раз, когда тип просто состоит из одногополе, а не оболочка.

6 голосов
/ 15 февраля 2012

Когда я создаю реальные программы, которые не выполняют тонких вещей с ленью, я почти всегда использую newtype для типов данных с одним конструктором и аргументами и data для всего остального:

data Foo = FooA | FooB Int
data Bar = BarA Int Foo
newtype Baz = Baz Bar

По крайней мере, если вы обнаружите, что пишете

newtype Foo = Foo (X,Y)

, семантика идентична

data Foo = Foo X Y

, так что вы можететакже используйте версию data, потому что она красивее.Действительно,

data Foo = Foo Int
newtype Bar = Bar Int

действительно различаются по семантике, но ни в коем случае не оказываются важными для «настоящих» программ, где мы не ожидаем, что должны знать разницу между _|_ и Foo _|_ (поскольку все значения в любом случае полностью определены).

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

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