Псевдонимы конструкторов Haskell
Есть ли способ создать что-то эквивалентное созданию псевдонимов конструктора в Haskell? Я думаю, что это похоже на псевдонимы типов, где вы можете дать типу другое имя, но он все равно ведет себя как псевдоним типа.
Мой вариант использования - это система, в которой у меня есть назначенное время как свойство некоторых объектов, которые я моделирую, поэтому UTCTime
, Некоторые из них могут быть "переменными", то есть, возможно, им еще не назначено время, или время, которое у него есть, является "подвижным". Так Maybe UTCTime
,
Но только некоторые объекты имеют переменное время. Другие имеют фиксированное время, которое система должна воспринимать как постоянную; переменная времени, назначенная в настоящее время конкретному времени, не обрабатывается так же, как фиксированное время. Который сейчас предлагает Either UTCTime (Maybe UTCTime)
; это либо фиксированное время, либо переменное время, которое может быть не назначено.
Общие типы, кажется, соответствуют тому, что я пытаюсь смоделировать очень хорошо, поэтому их использование кажется естественным. Но пока очевидно, что Either UTCTime (Maybe UTCTime)
Это не совсем очевидно, что это значит, поэтому некоторые описательные имена особого случая было бы неплохо.
Просто type Timeslot = Either UTCTime (Maybe UTCTime)
определенно очистил бы мои сигнатуры типов, но это ничего не значит для конструкторов. Я могу использовать что-то вроде bound = Just
чтобы получить имя для построения значений, но не для сопоставления с образцом.
На другом конце я могу определить пользовательский ADT с любыми именами, которые я хочу, но затем я теряю все предопределенные функции Either
а также Maybe
типы. Или, скорее, я буду применять трансформации туда и обратно все время (что, я полагаю, не хуже, чем ситуация с использованием newtype
обертки для вещей, только без гарантии эффективности, но я сомневаюсь, что это все равно будет узким местом). И я полагаю, чтобы понять код, используя общий Either
а также Maybe
функции манипулировать моим Timeslot
значения, которые мне понадобятся, должны знать, каким образом стандартные конструкторы сопоставляются с тем, что я хочу использовать в любом случае, и функции преобразования предоставят удобное принудительное определение этого отображения на основе компилятора. Так что, возможно, это хороший подход в конце концов.
Я почти уверен, что знаю Хаскелла достаточно хорошо, чтобы сказать, что нет такой вещи, как псевдонимы конструктора, но мне любопытно, есть ли какой-нибудь хак, о котором я не знаю, или какой-то другой хороший способ справиться с этой ситуацией.
2 ответа
"Синонимы шаблонов" могут быть объединены в ghc: http://ghc.haskell.org/trac/ghc/ticket/5144. В то же время есть также -XViewPatterns, который позволяет писать такие вещи, как:
type Timeslot = Either UTCTime (Maybe UTCTime)
fieldA = either Just (const Nothing)
fieldB = either (const Nothing) id
f (fieldA -> Just time) = ...
f (fieldB -> Just time) = ...
f _ = ...
Несмотря на упомянутые вами недостатки, я настоятельно рекомендую просто создать новый ADT для вашего типа; например
data TimeVariable = Constant UTCTime | Assigned UTCTime | Unassigned
Я предлагаю эти аргументы:
- Наличие описательных конструкторов сделает ваш код - как конструкцию, так и сопоставление с образцом - значительно более читабельным. сравнить
Unassigned
а такжеRight Nothing
, Теперь добавьте шесть месяцев и сделайте то же самое сравнение. - Я подозреваю, что по мере роста вашего приложения вы обнаружите, что этот тип должен расширяться. Добавление другого конструктора или другого поля к существующему конструктору намного проще с помощью пользовательского ADT, и с его помощью очень легко идентифицировать места кода, которые необходимо обновить для работы с новым типом.
- Вероятно, будет не так много разумных операций с этим типом, как в стандартной библиотеке для поиска.
Either
а такжеMaybe
значения - так что, держу пари, вы не будете дублировать столько кода, сколько думаете. И хотя вы, возможно, дублируете некоторый код, предоставление описательным именам ваших функций полезно по тем же причинам, что и читаемость, и по причинам, связанным с рефакторингом. - Я лично написал код, где все мои суммы были
Either
и все мои продукты были(,)
, Это было ужасно. Я никогда не мог вспомнить, какая сторона суммы означала какую вещь; при чтении старого кода мне приходилось постоянно напоминать себе, каким концептуальным типом должно быть каждое значение (например,Right
не говорит вам, используете ли выRight
здесь, как часть временной переменной или часть какой-то другой вещи, для которой вам было лень делать ADT); Мне приходилось постоянно мысленно расширять псевдонимы типов; и т. д. Учитесь на моей боли.;-)