Что является альтернативой прелюдии с qualfied import

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

import qualified Data.Map as Map
import qualified Data.Set as Set
import qualified Data.Text as Text

Я хотел бы определить локальную прелюдию, чтобы Map, Set и Text были доступны для модулей, импортирующих эту прелюдию. По-видимому , в Haskell нет никакого способа сделать это. Поэтому мне интересно, как люди решают эту проблему в больших базах кода Haskell.

Ответ 1

Одним из решений является определение списка импорта в заголовке CPP.

NB: Этот ответ - это просто показать, что технически возможно; Ответ Даниэля Вагнера, как правило, является лучшей альтернативой.


Для примера на уровне пакета:

my-pkg/
  my-pkg.cabal
  include/imports.h
  src/MyModule.hs
  ...

include/imports.h:

import Control.Applicative
import Data.Maybe
import Data.Char

В my-pkg.cabal компоненты (library, executable, test ,...) имеют поле include-dirs (что в свою очередь соответствует некоторой опции GHC):

library
  ...
  include-dirs: include

Затем вы можете использовать этот заголовок в любом модуле:

{-# LANGUAGE CPP #-}

module MyModule where

#include "imports.h"

-- your code here
mymaybe = maybe

Ответ 2

Я собираюсь ответить на этот вопрос, интерпретируя его как можно более буквально:

Как люди решают эту проблему в больших базах кода Haskell?

Ответ: они пишут

import qualified Data.Map as Map
import qualified Data.Set as Set
import qualified Data.Text as Text

в верхней части каждого модуля, который нуждается в Map, Set и Text.

По моему опыту, управление импортом не является существенной частью сложности работы с большими кодовыми базами. Усилия прыжка в список импорта и добавление строки для Data.Map когда вы обнаружите, что вам это нужно, абсолютно захлестнуто стремлением найти нужное место в кодовой базе для внесения изменений, зная полную ширину кодовой базы, чтобы вы не дублировать усилия и находить способы проверки небольших фрагментов большого приложения изолированно.

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

  • Меньше времени ввода проекта. Чем меньше сюрпризов для людей, которые присоединяются к вашему проекту, тем быстрее они могут встать и работать и быть независимо полезными.
  • Лучшая поддержка инструмента. Если я где-то вижу Foo.bar в качестве идентификатора, я могу использовать поиск в регулярном выражении текстового редактора, чтобы узнать, какая строка импорта сделала пространство имен Foo доступным без фантастических дополнений, чтобы включить #include d файлы. Если я хочу найти все файлы, которые зависят от Some.Fancy.Module, я могу узнать, что grepping для Some.Fancy.Module. Создавать системы, которые выполняют обнаружение изменений, не обязательно знать о дополнительном файле .h при .h файлов, которые нужно посмотреть. И так далее.
  • Меньше ложных перестроек. Если у вас больше импорта, чем вы на самом деле используете, это может привести к тому, что GHC перестроит ваш модуль, даже если его не нужно перестраивать.