Cannot set up servant app using stack - "Could not find module ‘Servant’" - haskell

I'm trying to set up basic project using servant and stack loosely following official servant tutorial and stack guide. As soon as I add import Servant stack build fails with:
Could not find module ‘Servant’
Use -v to see a list of the files searched for.
I've defined servant as a dependency of this module and stack noticed it as stack dependencies shows:
aeson 0.8.0.2
array 0.5.1.0
attoparsec 0.12.1.6
base 4.8.1.0
binary 0.7.5.0
blaze-builder 0.4.0.1
bytestring 0.10.6.0
bytestring-conversion 0.3.1
case-insensitive 1.2.0.4
containers 0.5.6.2
deepseq 1.4.1.1
dlist 0.7.1.2
double-conversion 2.0.1.0
ghc-prim 0.4.0.0
hashable 1.2.3.3
http-media 0.6.2
http-types 0.8.6
integer-gmp 1.0.0.0
mtl 2.2.1
network-uri 2.6.0.3
parsec 3.1.9
primitive 0.6
scientific 0.3.3.8
servant 0.4.4.2
string-conversions 0.4
syb 0.5.1
template-haskell 2.10.0.0
text 1.2.1.3
tforia-products 0.1.0.0
time 1.5.0.1
transformers 0.4.2.0
unordered-containers 0.2.5.1
utf8-string 1.0.1.1
vector 0.10.12.3
Code of module:
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeOperators #-}
module API
( ProductAPI
, apiServer
) where
import Data.Aeson
import GHC.Generics
import Servant
data Product = Product
{ id :: String
, name :: String
} deriving (Eq, Show, Generic)
instance ToJSON Product
products :: [Product]
products =
[ Product "id123" "shoes of some guy"
, Product "id234" "hat of some gal"
]
type ProductAPI = "products" :> Get '[JSON] [Product]
apiServer :: Server UserAPI
apiServer = return products
Cabal definition of module:
library
hs-source-dirs: src
exposed-modules: API
build-depends: base >= 4.7 && < 5
, servant
, aeson
default-language: Haskell2010
I have no idea where else I have to define that dependency so stack/cabal is able to pick it up.

The Servant module comes from servant-server, as you can see here in the module list. The handy Servant module reexports everything from the servant package (which has all the types to describe web APIs) as well as the key things for running servant web apps.
Long story short: you need to add the servant-server package to your dependencies as well.

Related

How to diagnose "Perhaps you need to add xxx to the build-depends in your .cabal file", when it is already in the cabal file?

I think the only interesting bits are my imports and my cabal file. Here are the imports and the demonstration of how I would use the problematic import (Database.CQL.IO.Log).
module FDS.Database.Cassandra where
import Prelude hiding(init)
import Database.CQL.IO as Client hiding(Logger)
import Database.CQL.IO.Log as CQLLog
import qualified Database.CQL.Protocol as CQL
import Numeric.Natural
import System.Logger (Logger)
cqlLogger :: Logger -> CQLLog.Logger
cqlLogger logger = undefined
However, I get the error:
src/FDS/Database/Cassandra.hs:7:1: error:
Could not load module `Database.CQL.IO.Log'
It is a member of the hidden package `cql-io-1.1.0'.
Perhaps you need to add `cql-io' to the build-depends in your .cabal file.
Use -v to see a list of the files searched for.
|
7 | import Database.CQL.IO.Log as CQLLog
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
But as we can see from the cabal file, it is there:
library
ghc-options: -Wall -Wtabs -Wincomplete-record-updates
default-extensions:
OverloadedStrings
exposed-modules:
FDS
, FDS.Config.Core
, FDS.Config.Dhall
, FDS.Data.Util
, FDS.Database.Cassandra
other-modules:
FDS.Data.Hobo.Defs
build-depends:
prelude
, base-noprelude ^>=4.12
, bytestring ^>=0.10.8.2
, conduit ^>=1.3.1
, containers ^>=0.6
, cql ^>=4.0.1
, cql-io ^>=1.1.0
One thing to note, I do have cql-io in my extra-deps in stack.yaml, as the latest version wasn't yet in LTS.
Q&A from Comments
Q Are there other components in your cabal file (e.g. executables, benchmarks, test suites)?
A Yes
Q Do they also use FDS.Database.Cassandra (but perhaps without depending on cql-io)?
A Not yet, but plan to later. So I haven't touched the other components yet.
Q Does the version of cql-io chosen by your build tool still export Database.CQL.IO.Log?
A It seems to do so.
Q What is the exact command you are running when you see that error?
A stack --nix build The only interesting bit that --nix is doing (AFAIK) is pulling in required system packages, e.g., OpenSSL.
The comments above were very insightful for the general case of the question (as posed); the answer being, sub-libraries that are recently supported by cabal may not have visibility: true declared.
But in my specific case, the answer is to look at the problematic library's re-exports. I could get around this issue because the cql-io authors re-exported Logger (..) and LogLevel(..) from the main library.
So that would allow me to write my code.
An even better answer that is very specific to my situation, as I was trying to use TinyLog, is that there is a library for that already ... here is the code from that library that demonstrates how to get around the issue (and solves the problem for me completely, as I now shouldn't have to write any code).
Here is the relevant excerpt:
module Database.CQL.IO.Tinylog (mkLogger) where
import Data.ByteString.Builder
import Data.ByteString.Lazy (ByteString)
import Database.CQL.IO (Logger (..), LogLevel (..))
import Database.CQL.IO.Hexdump
import qualified Data.ByteString.Lazy as L
import qualified System.Logger as Tiny
-- | Create a cql-io 'Logger' that delegates log messages to
-- the given tinylog 'Tiny.Logger'. Requests and responses are
-- logged on 'Tiny.Trace' level.
mkLogger :: Tiny.Logger -> Logger
mkLogger l = Logger
{ logMessage = tinylogMessage l
, logRequest = tinylogRequest l
, logResponse = tinylogResponse l
}
And here is how I adjusted my imports in the example above to confirm and get GHC happy (though I will scrap this now in favor of using cql-io-tinylog):
import Prelude hiding(init, log)
import Database.CQL.IO hiding(Logger)
import qualified Database.CQL.IO as CQLIO
import qualified Database.CQL.Protocol as CQL
import Numeric.Natural
import System.Logger hiding(defSettings)

Importing sub-packages with stack

I don't understand how to import "sub-packages" in stack (if this is not the correct term, please let me know so I can edit).
Here's the top of a simple file:
{-# LANGUAGE OverloadedStrings #-}
module Conduit where
import Data.Conduit
import qualified Data.Conduit.List as CL
import qualified Data.Conduit.Binary as CB
Two dependencies are listed. In myproject.cabal, I have:
executable myproject
hs-source-dirs: src
main-is: Main.hs
default-language: Haskell2010
build-depends: base >= 4.7 && < 5,
conduit
stack build -v gives me this error:
2018-02-08 13:28:06.923836: [warn] 7 | import qualified Data.Conduit.Binary as CB
I am not sure what to include in the cabal executable directive, each of these throws errors:
build-depends: base >= 4.7 && < 5,
conduit,
conduit.list,
conduit.binary
build-depends: base >= 4.7 && < 5,
conduit,
conduit-list
conduit-binary
Data.Conduit.Binary is a module. It is part of a package called conduit-extra. Packages are what Stack (and cabal-install, were you using that instead) installs, and what you should add to the build-depends of the .cabal file:
build-depends: base >= 4.7 && < 5,
conduit,
conduit-extra
As for Data.Conduit.List, it is part of the conduit package, so you don't need another entry for it. One quick way of clarifying such things is doing a Hoogle search for the module (the package it belongs to will be pointed out in the top bar of the documentation page).
See also: What's the difference between module, package and library in Haskell?; Packages, modules and import in Haskell.

How do I install and test a Haskell package that I'm developing locally?

I'm developing a Haskell package and would like to test it as if it were an installed package. That is, I'd like to be able to install it among my other packages and then either import or :m +.
I can successfully build my package and (apparently) can successfully install it using
cabal install
which reports
Resolving dependencies...
Configuring Exos-0.0.1.0...
Building Exos-0.0.1.0...
Installed Exos-0.0.1.0
but all attempts to import the package then fail with something like (e.g. in GHCi)
<no location info>:
Could not find module ‘Exos’
It is not a module in the current program, or in any known package.
even though I can see a populated Exos-0.0.1.0 folder in my Haskell lib directory. (Even "uninstalling" fails with ghc-pkg unregister, which reports ghc-pkg: cannot find package Exos-0.0.1.0.)
How do I install and test a package that I'm developing locally, so that it behaves like part of my collection of installed Haskell packages — specifically so that I can import it (and "uninstall" it) like any other?
My package has the structure
Exos.cabal
Exos/
Cryo/
Exos.hs
Exos/
Display.hs
Core.hs
with (relevant) contents in Exos.cabal
name: Exos
version: 0.0.1.0
build-type: Simple
- ...
library
exposed-modules: Cryo.Exos,
Cryo.Exos.Display
other-modules: Cryo.Exos.Core
-- other-extensions:
build-depends: base >=4.8,
containers >= 0.5.5.1,
split >= 0.2.2,
MissingH >= 1.3.0.1
-- hs-source-dirs:
default-language: Haskell2010
in Exos.hs
module Cryo.Exos
(
f,
g,
otherFunc
) where
import Cryo.Exos.Core
-- ...
in Core.hs
module Cryo.Exos.Core where
-- ...
and in Display.hs
module Cryo.Exos.Display
(
showSomething,
showSomethingElse
) where
import Data.Char
-- ...
import Cryo.Exos.Core
import Cryo.Exos
FWIW, inside my IDE, I can write an and successfully run "Application" with the following section in the above .cabal file
executable enigma-hs
main-is: Main.hs
build-depends: base >=4.8,
Exos
hs-source-dirs: tests
default-language: Haskell2010
and the following (relevant) code in Exos/tests/Main.hs
module Main where
import System.IO
import Cryo.Exos
import Cryo.Exos.Display
main :: IO ()
main = do
putStr $ showSomething
putStr $ showSomethingElse
-- ...
The error is a simple one: If you look at the Main.hs example where you have successfully imported the module you have
import Cryos.Expos
and not
import Expos -- wrong
that's because, the module you are importing is Cryos.Expos from the package Expos.

Type Error when Extracting Post Request

I'm trying to extract a basic post request using code from this question (except that I'm using lbsBackEnd instead of the no-longer-existing lbsSink).
{-# LANGUAGE OverloadedStrings #-}
import Network.Wai.Handler.Warp (run)
import qualified Data.ByteString.Char8 as C
import Network.Wai.Parse (parseRequestBody, lbsBackEnd)
import Network.Wai(Response(..))
import Network.HTTP.Types(status200)
import Blaze.ByteString.Builder
main = run 3000 app
app req = do
(params, _) <- parseRequestBody lbsBackEnd req
let r = C.concat $ map (\(x,y) -> C.concat [x,y]) params
return $ ResponseBuilder
status200
[("Content-Type", "text/plain")]
$ fromByteString r
Comments in that question suggest that this should work, but I'm getting the type error
Couldn't match expected type `C.ByteString'
with actual type `bytestring-0.9.2.1:Data.ByteString.Internal.ByteString'
Expected type: [(C.ByteString, C.ByteString)]
Actual type: [Network.Wai.Parse.Param]
In the second argument of `map', namely `params'
In the second argument of `($)', namely
Which is a bit odd because Network.Wai.Parse docs say that Param is a type synonym for (ByteString, ByteString), so as far as I can tell, this should work.
Any tips on what I'm doing wrong?
Your wai-extra was built using bytestring-0.9.2.1, but you have a newer bytestring package installed. Unless GHC is instructed to use the older version with a -package flag or by hiding the newer, it picks the newest installed version of each package.
The package version is part of the types it defines, so the ByteString of bytestring-0.9.2.1 is not the same type as the ByteString of bytestring-0.10.0.0 (or whatever your newest version is).
You can
compile the programme with a -package bytestring-0.9.2.1 flag (but it could be that other used packages are built against a different bytestring version, then that wouldn't work).
build the programme as a Cabalized package, then cabal-install would figure out the necessary -package flags and provide them to GHC (if it finds a consistent build plan).
rebuild wai-extra (and possibly a lot of other packages) against the newer bytestring version.
unregister the newer bytestring version (which might require rebuilding some packages using the old version).

How to build and use a bootstrap executable in a Cabal package

I would like to Cabalize a Haskell project in order to upload it to Hackage. It consists of one standard .hs file which builds a bootstrap executable, and eight nonstandard .lhs files which are processed by the bootstrap executable to yield the .hs files which build the production executable.
In other words, my project is a custom literate preprocessor (with HTML markup, code grooming, here documents) which is written in itself. It depends on a bootstrap version which can translate the literate code for the production version, but which is not suitable for general use. So I do not want the bootstrap version to be a separate package; it is meant to be used only once, here.
I have been using a Makefile, which is possible in Cabal but not in the spirit of Cabal. What is a clean way to do this, that takes maximal advantage of the generality of Cabal? I have not seen any suggestions for this in the online documentation, short of either rewriting Distribution.Simple or using a Makefile.
I think that releasing your bootstrap executable as a separate package is the easiest solution, and there are instructions available on how to integrate your custom preprocessor with Cabal.
If you don't want to do that, try making your preprocessor part of Setup.hs (don't forget to set the build type to Custom!). You can run your preprocessor during the configure step. Look at how wxcore does this.
Here's a working example (patterned after wxcore):
Setup.hs:
import Distribution.Simple
import Distribution.Simple.LocalBuildInfo
import Distribution.Simple.Setup
import Distribution.PackageDescription
import Control.Monad (forM_)
import System.Directory (copyFile)
import System.FilePath (replaceExtension)
main :: IO ()
main = defaultMainWithHooks simpleUserHooks { confHook = myConfHook }
-- Replace 'copyFile' with more complicated logic.
runMyPreprocessor :: FilePath -> IO ()
runMyPreprocessor abcFile = copyFile abcFile (replaceExtension abcFile ".hs")
myConfHook :: (GenericPackageDescription, HookedBuildInfo) -> ConfigFlags
-> IO LocalBuildInfo
myConfHook (pkgDesc, hbi) flags = do
let extraSrc = extraSrcFiles . packageDescription $ pkgDesc
forM_ extraSrc runMyPreprocessor
confHook simpleUserHooks (pkgDesc, hbi) flags
my-preprocessor.cabal:
name: my-preprocessor
version: 0.1.0.0
build-type: Custom
cabal-version: >=1.8
extra-source-files: Main.abc
executable my-preprocessor
main-is: Main.hs
build-depends: base < 5
Main.abc:
module Main
where
main :: IO ()
main = putStrLn "Hello"

Resources