Matvei Kazyukevich
Matvei Kazyukevich

Reputation: 1

Could not find module. How to fix this problem?

I have 2 files Base.hs and Entities.hs. These files are in the same folder. And Base import in Entities.

Base.hs:

module Data.Base (Color(..)) where

data Color = White | Black | Other
    deriving (Show)

Entities.hs:

module Data.Entities (Product(..), Shop(..), Order(..), Customer(..), productID, productName, productPrice, productColor) where

import Data.Base (Color(..))

type ProductID = Int
type ProductName = String
type ProductPrice = Double
type ProductColor = Color

data Product = Product ProductID ProductName ProductPrice ProductColor
    deriving (Show)

productID :: Product -> ProductID
productID (Product pid _ _ _) = pid

productName :: Product -> ProductName
productName (Product _ name _ _) = name

productPrice :: Product -> ProductPrice
productPrice (Product _ _ price _) = price

productColor :: Product -> ProductColor
productColor (Product _ _ _ color) = color

data Shop = Shop {
      shopID :: Int
    , shopName :: String
    , shopAddress :: String
} deriving (Show)

data Customer = Customer {
      customerID :: Int
    , customerName :: String
    , customerAddress :: String  
} deriving (Show)

data Order = Order {
      orderID :: Int
    , orderNumber :: String 
} deriving (Show)

When I run a project, I have a mistake in Entities.hs:

 Could not find module `Data.Base'
    Use -v (or `:set -v` in ghci) to see a list of the files searched for.
  |
3 | import Data.Base (Color(..))

  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Structure of my project:

└── Project
    └── src
        └── Data
            ├── Base.hs
            └── Entities.hs

How to fix this mistake?

Project's building is successfully, so the error may come out because of some vs code plugin. But I do not know how to solve it

Upvotes: 0

Views: 1666

Answers (1)

Ben
Ben

Reputation: 71400

You haven't told us what you mean by "building" the project (which you say is successful), and "running" the project. The error you're reporting is clearly a compile-time error, not an error you can receive when running already built code. But there are several options for what you might mean by "run" that would have to recompile the code first (such as loading a Haskell file into ghci and then typing Haskell commands to work with your code, or using runhaskell on a Haskell file to execute your code as a shell command).

As chi noted in a comment, an import like import Data.Base will look for a file Base.hs inside a directory called Data. So you don't just want to have Base.hs and Entities.hs in the root folder of your source tree; where you have those files you should actually have a single folder called Data, and inside that you should have Base.hs and Entities.hs.

However, if you already have this and then you enter the folder where your files are (the Data folder), and then type ghci Entities.hs or runhaskell Entities.hs (or anything similar) you'll still get the error!

(I'm assuming by "when I run a project" you mean go into ghci

That's because the compiler can't read your mind to know which folder you consider to be the "root" of your source tree. Say you have this file tree:

.
└── CodingStuff
    └── ThisProject
        └── Data
            ├── Base.hs
            └── Entities.hs

How is the compiler supposed to know that the file Base.hs should be "addressed" in the Haskell module space as Data.Base? It could also be just Base, or ThisProject.Data.Base or CodingStuff.ThisProject.Base. So what it does when you simply tell it to run a file with no other configuration is consider the working directory as the "root". So to run Entities.hs that way you need to be in the folder above your Data folder, not in the folder that actually has your two files in it. Then you can simply run ghci Data/Entities.hs (or ghci Data.Entities) and it will work.

The normal way Haskell developers address this is to make their code into a formal package1, using a .cabal file (or a package.yaml file if using stack). Then cabal (or stack) uses the contents of this file to tell it where your source tree is rooted and what modules exist, so you can then cabal repl to start an interpreter session2, or cabal run to build an run an executable in your package. Or, of course, if your project is an executable and you're building your project (which you say was successful), why aren't you running the built executable? If you're using ghci or runhaskell you're compiling it again every time you run it, and probably without much optimisation.

If you don't want to learn how Haskell packages work (and a tool like cabal), that's probably perfectly reasonable if your project is just a couple of files that don't need any libraries. In that case I would recommend you ditch the Data. prefix on your module names. Just call them module Base and module Entities, put them in the same folder, and you can ghci from that folder with no complications. If your project gets big enough that you actually want to use folders to organise your files, OR if you need to install any external libraries, then you really should learn the packaging tools. It will seem daunting but it honestly is way less hassle to learn cabal than it is to learn how to deal with all of the problems you will run into by not using a package.

And honestly, for the files you have shown I would ditch the Data prefix anyway. I imagine you've used it because you've seen lots of modules you had to import that started with Data and assumed they're doing it for a reason so you should too. But Data is a very general namespace with a lot in it. In my opinion it really shouldn't be used much by "end user" code, and should be left to widely applicable libraries that will be published on Hackage. Otherwise everything ends up in Data, and if everything is in the same namespace you migth as well not have used the namespace at all. In particular, the Data prefix is so widely used across so many libraries that you absolutely should not claim highly general names like Base and Entities directly under the Data namespace. If those are specific to your project then you should probably just use a prefix derived from your project name if this is a library, or maybe even no prefix at all if these modules are part of an executable.

(Executables can't be imported into other projects, so they don't need to worry as much about picking names that will be descriptive in some other context sitting alongside unknown other libraries. The module names only need to identify them in the context of this one specific project, where you know everything else that's being used so you know exactly what thee might be confused with. This means it's often actually helpful to use prefix-less names specifically to make your "local" modules easy to spot amongst all the other modules you're importing, because they don't start with Data or Control or one of thee other common prefixes. The same goes for non-exposed modules in libraries)


1 You mention VS Code; it may have already done this for you, and if not it almost certainly has an easy option to do so. But I've never used VS Code with Haskell (and not at all for many years), so I don't know precisely how it works.


2 Or an equivalent stack command. Stack and cabal are both tools to manage Haskell projects. You can use whichever you like. I'm going to stop adding "or stack" to everything I say about cabal from now on.

Upvotes: 3

Related Questions