Hello Haskell community,
I'm new to Haskell and ran into a problem when I tried to structure my first bigger project.
Here's the minimal example of the problem (I'm using cabal to build).
This is the directory structure of a simple module:
FooMod1
|- FooMod1.cabal
|- Setup.hs
|- src
|- FooMod1.hs
|- FooMod1
|- C1.hs
|- T1.hs
The source for FooMod1.hs:
module FooMod1 (
C1(..) ,
T1(..) ,
) where
import FooMod1.C1
import FooMod1.T1
The source for C1.hs:
module FooMod1.C1 (
C1(..)
) where
class C1 a where
c1FooFun :: a -> IO ()
The source for 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"
The source for the cabal file:
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
and the Setup.hs:
module Main where
import Distribution.Simple
main = defaultMain
I can do
cabal configure
cabal build
cabal install
without any problem. When I start ghci and
import FooMod1
it loads the module and I can see the data constructors. But when I try to get the type of a function for example
:t c1FooFun
or construct a value I get:
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' reveals nothing.
What am I missing? I looked it up in the Haskell 2010 Standard ( http://www.haskell.org/onlinereport/haskell2010/haskellch5.html ) and i can't find the error. So my questions are
1) Why am I getting this error?
2) Is structuring a hierarchical modules like that good practice? (assume considerably larger programs)
Many thanks in advance!
Jules
Edit: September 2016
Since I originally answered this question there is a growing practice of defining Foo.Internal
modules that are still exposed. In the original answer below I suggested using the other-modules
field. A practice that is now popular is to define Foo.Internal.*
modules that are exposed but explicitly not part of the supported API. The rational for this pattern is explained in the answers to this question .
As noted in the comments your .cabal
file is missing the other-modules
line. I think cabal install
then only installs FoodMod1
since that is all it's been told about.
This is a nice way to create internal modules with, for instance, types that are used throughout your cabal package which you don't want to expose in the package API. Since the other-modules
modules cannot be imported from outside your package it allows you to create package private functionality.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.