Ошибка "Ошибка загрузки интерфейса" при загрузке скомпилированных модулей в ghci

Привет, сообщество Haskell,

Я новичок в Haskell и столкнулся с проблемой, когда попытался структурировать свой первый крупный проект.

Вот минимальный пример проблемы (я использую cabal для сборки).

Это структура каталогов простого модуля:

FooMod1
|- FooMod1.cabal
|- Setup.hs
|- src
  |- FooMod1.hs
  |- FooMod1
    |- C1.hs
    |- T1.hs

Источник для FooMod1.hs:

module FooMod1 (
    C1(..) ,
    T1(..) ,
) where 

import FooMod1.C1
import FooMod1.T1

Источник для C1.hs:

module FooMod1.C1 (
    C1(..)
) where

class C1 a where
    c1FooFun :: a -> IO ()

Источник для T1.hs:

module FooMod1.T1 (
    T1(..)
) where

import FooMod1.C1

data T1 = T1 deriving(Show)

instance C1 T1 where
    c1FooFun T1 = putStrLn "c1FooFun from T1"

Источник для файла cabal:

Name:                      FooMod1
Version:                   0.0.1
Cabal-version:             >=1.10
Build-type:                Simple

library 
  build-depends:           base >= 4 && < 5
  if impl(ghc >= 7.0.0)
     default-language:     Haskell2010
  ghc-options:             -Wall
  exposed-modules:         FooMod1

  ghc-options:             -Wall -rtsopts
  hs-source-dirs:          src, src/FooMod1
  default-language:        Haskell2010

и Setup.hs:

module Main where

import Distribution.Simple

main = defaultMain

Я могу сделать

cabal configure
cabal build
cabal install

без проблем. Когда я запускаю ghci и

import FooMod1

он загружает модуль, и я вижу конструкторы данных. Но когда я пытаюсь получить тип функции, например

:t c1FooFun

или построить значение, которое я получаю:

Failed to load interface for `FooMod1.C1'
There are files missing in the `FooMod1-0.0.1' package,
try running 'ghc-pkg check'.
Use -v to see a list of the files searched for.
In the expression: c1FooFun

'ghc-pkg check' ничего не показывает.

Что мне не хватает? Я просмотрел его в стандарте Haskell 2010 (http://www.haskell.org/onlinereport/haskell2010/haskellch5.html), и я не могу найти ошибку. Поэтому мои вопросы:

1) Почему я получаю эту ошибку?

2) Является ли структурирование иерархических модулей такой хорошей практикой? (предполагают значительно большие программы)

Большое спасибо заранее!

Жюль

Ответы

Ответ 1

Изменить: сентябрь 2016 года

Поскольку я первоначально ответил на этот вопрос, растет практика определения модулей Foo.Internal, которые все еще отображаются. В первоначальном ответе ниже я предложил использовать поле other-modules. Популярной практикой является определение Foo.Internal.* модулей, которые отображаются, но явно не являются частью поддерживаемого API. Рациональное для этого шаблона объясняется в ответах на этот вопрос.


Как отмечено в комментариях, в файле .cabal отсутствует строка other-modules. Я думаю, cabal install тогда устанавливает только FoodMod1, так как это все, о чем было сказано.

Это хороший способ создания внутренних модулей, например, типов, которые используются во всем пакете cabal, который вы не хотите раскрывать в API пакета. Поскольку модули other-modules не могут быть импортированы извне вашего пакета, это позволяет вам создавать частные функции пакета.