Как мне работать с инфиксными символами, выглядящими безобразно с квалифицированными именами - PullRequest
10 голосов
/ 28 января 2012

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

Однако я чувствую, что необходимость помещать пространство имен в символ инфикса (или другие короткие идентификаторы DSL-y) выглядит действительно страннопоэтому у меня возникает соблазн реэкспортировать значения, например:

import qualified Data.Sequence as Seq
(|>) = (Seq.|>)
(<|) = (Seq.<|)

Что меня беспокоит, так это то, что

  • Ручной реэкспорт значений выглядит как скучный шаблон.

  • Ручной реэкспорт значений проходит по существующей модульной системе и, похоже, не работает с конструкторами данных (и, возможно, с другими вещами, с которыми я еще не сталкивался)

    import qualified Data.Sequence as Seq
    (:>) = (Seq.:>)  --gives me a parse error:
                     --"Not in scope: data constructor `:>'"
    

Как согласовать инфиксные символы и пространство имен? Должен ли я просто сдаться и научиться все пространство имен?Существуют ли лучшие практики Haskell в отношении пространства имен и символов?

Ответы [ 2 ]

19 голосов
/ 28 января 2012

Ну, одну вещь, которую вы можете сделать, это импортировать ее дважды:

import Data.Sequence ((|>), (<|), ViewR ((:>)))
import qualified Data.Sequence as Seq

Это импортирует только :>, |> и <| без оговорок, оставляя все остальное квалифицированным.Обратите внимание, что поскольку :> является конструктором данных, вам также необходимо импортировать его тип данных (ViewR), но вы не должны импортировать остальные конструкторы ViewR.

Кроме того, если вы беспокоитесь о конфликтах, вам следует просто скрыть соответствующий оператор:

import Prelude hiding ((.))

Если вы используете разумную библиотеку, конфликт с Prelude означает, что библиотечная функцияпредназначен для замены этой функции Prelude (например, Control.Category), поэтому вы хотите, чтобы она заменяла значение по умолчанию.

Что касается передового опыта, я никогда не видел, чтобы кто-либо использовал квалифицированные операторыесли нет конфликта или они в GHCi.В целом, даже если учесть преимущество знания оператора, он делает код гораздо менее читабельным.

8 голосов
/ 28 января 2012

Обычно я импортирую имена типов, конструкторы и операторы без оговорок, а все остальное уточняется:

import Data.Sequence (Seq, ViewL(..), ViewR(..), (|>), (<|))
import qualified Data.Sequence as Seq

Этот стиль с двойным импортом без указания типа имен рекомендуется в документации для Данные.Map и другие стандартные контейнеры.

Тем не менее, вы не всегда можете импортировать неквалифицированные операторы - например, если вы используете Array / Vector и Map в одном и том же модулеВы не можете импортировать (!) из обоих неквалифицированных.В этом случае, я бы просто использовал его квалифицированно.Это выглядит странно, но это лучше, чем другие варианты (например, придумать свое имя для одного из них, чтобы избежать столкновения).Конечно, возможно, это хорошо, если это мешает людям использовать небезопасные функции, такие как (Data.Map.!):)

...