Я пытаюсь понять структуру базового пакета, отображаемую Hackage. После https://en.wikibooks.org/wiki/Haskell/Modules имя модуля должно отражать путь к его источнику; процитирую выше:
The name of the file is the name of the module plus the .hs file extension. Any dots '.' in the module name are changed for directories.
Взяв в качестве примера Data.List, я пришел к выводу, что должен быть исходный файл по пути ../Data/List.hs, который затем содержит
module Data.List where ...
(список экспорта по модулю).
С другой стороны, если я просматриваю модуль Data.List на Hackage и перехожу по ссылкам «# Source», меня перенаправляют к исходным файлам для различных модулей. Среди них: GHC.Base, Data.OldList, Data.Foldable, GHC.List.
Во-первых, моя локальная установка базового пакета явно содержит файл интерфейса ../Data/List.hi.
Поэтому мой вопрос: Чем объяснить это несоответствие? Что на самом деле демонстрируется на Hackage?
Заранее благодарим за понимание по этому поводу!
Имена, импортированные из модулей, можно повторно экспортировать. Когда это происходит, пикша помогает связать вас с исходным источником имени, а не со строкой импорта в модуле реэкспорта; он следует за вами косвенным указанием. Вот что происходит в вашем случае. Итак, взяв в качестве примера (++)
(первая функция в пикше для Data.List), код структурирован следующим образом:
-- GHC/Base.hs
module GHC.Base where
(++) = ...
-- Data/OldList.hs
module Data.OldList ( (++) {- re-exports GHC.Base's (++) -}, ... ) where
import GHC.Base -- brings (++) into scope
-- Data/List.hs
module Data.List ( (++), ... ) where
import Data.OldList hiding ( ... {- does not mention (++) -} )
Итак, вы можете видеть, что пикша фактически перешла по ссылкам два: (++)
был импортирован из Data.OldList
, и даже там он был реэкспортом.
Компилятор также внимательно отслеживает исходный модуль, который определил имя; если вы импортируете все Data.List
, Data.OldList
и GHC.Base
, вы обнаружите, что все еще можете использовать (++)
, даже если на первый взгляд может показаться неоднозначным, какой из (Data.List.++)
, (Data.OldList.++)
или (GHC.Base.++)
вы имели в виду. Поскольку все три фактических в конечном итоге разрешаются в (GHC.Base.++)
, двусмысленности нет.