Haskell Crypto Hash SHA256 replit failure - haskell

I'm trying to hash text using Crypto.Hash modules on replit.com, I don't know how to resolve this failure: Could not find module ‘Crypto.Hash’
Code:
import Crypto.Hash (hashWith, SHA256(..))
import Data.ByteString (ByteString)
main = do
putStrLn "Hello"
putStrLn "World"
hashWith SHA256 ("hello" :: ByteString)
I will be very grateful for your help!!!

It looks like replit.com is Nix based, and it uses a replit.nix configuration file to configure the Nix environment, including loaded GHC packages.
So, one way to get this working is to edit the replit.nix file. (By default, it won't be shown in the "Files" tab, but you can click the vertical "..." in the top-right corner and select "Show hidden files" to view it.) Modify it to look something like:
{ pkgs }: {
deps = [
(pkgs.haskellPackages.ghcWithPackages (pkgs: [
pkgs.cryptonite
]))
pkgs.haskell-language-server
];
}
Now, when you run the source, it should reconfigure the Nix environment and load the required cryptonite package. You may need to modify your code slightly, too, as it uses an OverloadedStrings extension, and hashWith isn't an IO action. I got the following Main.hs to work:
{-# LANGUAGE OverloadedStrings #-}
import Crypto.Hash (hashWith, SHA256(..))
import Data.ByteString (ByteString)
main = do
print $ hashWith SHA256 ("hello" :: ByteString)

Related

GHCi can't load script that imports `Data.Set` or `Data.Maybe` if external package is imported

I have a script
#!/usr/bin/env stack
{-# LANGUAGE QuasiQuotes #-}
module Script where
import qualified Data.Set as Set (Set, fromList)
import Data.Maybe (fromJust)
{- import Text.RawString.QQ not neccessary for demonstration -}
main :: IO()
main = print "foo"
That I run with stack --resolver lts-12.5 runghc --package raw-strings-qq Script.hs
But I can't load it in GHCi:
$ stack ghci --resolver lts-12.5 --package raw-strings-qq
Note: No local targets specified, so a plain ghci will be started with no package hiding or package options.
If you want to use package hiding and options, then you can try one of the following:
* If you want to start a different project configuration than /home/t/.stack/global-project/stack.yaml, then you can use stack init to create a new
stack.yaml for the packages in the current directory.
* If you want to use the project configuration at /home/t/.stack/global-project/stack.yaml, then you can add to its 'packages' field.
Configuring GHCi with the following packages:
GHCi, version 8.4.3: http://www.haskell.org/ghc/ :? for help
Loaded GHCi configuration from /tmp/haskell-stack-ghci/2a3bbd58/ghci-script
Prelude> :load Script.hs
[1 of 1] Compiling Script ( Script.hs, interpreted )
Stacko.hs:7:1: error:
Could not find module ‘Data.Set’
Perhaps you meant Data.Int (from base-4.11.1.0)
Use -v to see a list of the files searched for.
|
7 | import qualified Data.Set as Set (Set, fromList)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Failed, no modules loaded.
Own research:
I can load the file if I start ghci with just stack ghci --resolver lts-12.5.
Interestingly, when I import Data.Set 'unqualified' as I do with Data.Maybe:
import Data.Set
import Data.Maybe
the error persists, but when I drop the Data.Set import all together I can load Script.hs
Imports that don't work: Data.Set, Data.Map.Strict
Imports that work: Data.List, Data.Function, Data.Maybe
packages that produce the error: raw-strings-qq, HUnit

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)

How do I use PackageImports properly in ghci?

I want to do testing in ghci and I'm running into problems with similarly named modules in different packages (this is basically a continuation of my previous question: What should I do if two modules share the same name?)
The packages in question are crypto-api, cryptonite, and DRBG. They all provides modules involving Crypto.Random. I'm using PackageImports in ghci to work fix this issue.
However, it seems that the order of using PackageImports is important.
This works (in ghci):
:set -XPackageImports
import Crypto.Random.DRBG
import "crypto-api" Crypto.Random
This does not work:
:set -XPackageImports
import "crypto-api" Crypto.Random
import Crypto.Random.DRBG -- Error!
Also this does not work:
:set -XPackageImports
import "crypto-api" Crypto.Random
import "DRBG" Crypto.Random.DRBG -- Error!
The error that appears is:
<interactive>:1:1: error:
Ambiguous interface for ‘Crypto.Random’:
it was found in multiple packages:
crypto-api-0.13.2 cryptonite-0.23
Am I doing something wrong or is this a bug?
Perhaps the easiest way is to avoid PackageImports and instead rename the packages when starting ghci, using the -package option:
ghci -package "crypto-api (Crypto.Random as A)" -package "cryptonite (Crypto.Random as B)"
Once in ghci, you could import the renamed modules:
Prelude> import A
Prelude A> import B
Prelude A B>
The syntax -package "crypto-api (Crypto.Random as A)" makes only the Crypto.Random module available to ghci, but not the other modules in the package.
According to the Thinning and renaming modules section of the GHC user guide:
We also support renaming of modules, in case you need to refer to both
modules simultaneously; this is supporting by writing OldModName as
NewModName, e.g. -package "base (Data.Bool as Bool). You can also
write -package "base with (Data.Bool as Bool) to include all of the
original bindings (e.g. the renaming is strictly additive).
So perhaps it's better to write the options like -package "crypto-api with (Crypto.Random as A)" to maintain access to all the modules.
Using PackageImports instead of thinning and renaming modules has the problem that it makes the source code dependent on the precise packages in which imported modules live. If a module changes packages that breaks the program.
Why would you expect that to work at all?
:set -XPackageImports
import "crypto-api" Crypto.Random
import Crypto.Random.DRBG -- Error!
import "DRBG" Crypto.Random.DRBG -- Error!
You have imported the DRBG module twice and from the same package. From your question I thought you'd want to get the Crypto.Random modules from crypto-api and cryptonite but I don't see any attempt to use cryptonite at all here.
Just so we're clear, I can reproduce the error I think you were getting via GHCi:
Prelude> :set -XPackageImports
Prelude> import "crypto-api" Crypto.Random as OriginalRandom
Prelude OriginalRandom> import "cryptonite" Crypto.Random as ConflictRandom
<interactive>:1:1: error:
Ambiguous module name ‘Crypto.Random’:
it was found in multiple packages:
crypto-api-0.13.2 cryptonite-0.24
But it all works when you load it from a file so this is just a bug and can be avoided:
% cat t.hs
{-# LANGUAGE PackageImports #-}
import "crypto-api" Crypto.Random as OriginalRandom
import "cryptonite" Crypto.Random as ConflictRandom
import Crypto.Random.DRBG -- This only appears in one package
% ghci t.hs
GHCi, version 8.2.1: http://www.haskell.org/ghc/ :? for help
Loaded GHCi configuration from /Users/tommd/.ghci
[1 of 1] Compiling Main ( t.hs, interpreted )
Ok, 1 module loaded.
*Main>
Notice that DRBG is not part of this discussion. It doesn't have any conflicting modules names with anything on hackage as far as I know.

Error: "Failed to load interface for 'Data.Either.Utils'"

Does anyone know why this single, specific import statement is causing a problem? I'm using sandbox and cabal. My other imports work fine (Web.Scotty, Data.Text.Lazy, etc.). I'm running with "cabal exec runghc filename.hs". I don't have a cabal.config file, but I do have a cabal.sandbox.config file.
I'm attempting to use the forceEither function, which is in Data.Either.Utils. My import statements are normal as far as I can tell:
{-# LANGUAGE OverloadedStrings #-}
import Web.Scotty
import Control.Monad.Trans (liftIO)
import Data.Aeson (object, (.=))
import Network.HTTP.Types.Status
import Data.Text.Lazy
import Data.Text.Lazy.IO
import Data.Either.Utils
import Data.Monoid (mconcat)
Message:
filename.hs:8:1: error:
Failed to load interface for ‘Data.Either.Utils’
Use -v to see a list of the files searched for.
Running with -v shows:
Using a sandbox located at
/Users/myuser/Desktop/mydirectory/myotherdirectory/.cabal-sandbox
/usr/local/bin/ghc --print-global-package-db
/usr/local/bin/runghc filename.hs
The Data.Either.Utils module is not part of "base" Haskell; it's part of the MissingH package, and that package seems to be .. ha ha .. missing!
I'm not too familiar with Cabal sandboxes (I use Stack), but presumably you can run:
cabal install MissingH
in your sandbox, and you should be good to go.
If that doesn't work, just copy the code for forceEither from MissingH:
forceEither :: Show e => Either e a -> a
forceEither (Left x) = error (show x)
forceEither (Right x) = x

Using `version` from Paths_* in a Yesod application

I am trying to write a GET handler in Yesod that returns the application version.
Here is the Haskell code for the handler:
{-# LANGUAGE OverloadedStrings #-}
module Handler.Version where
import qualified Data.Text as T
import Data.Version (showVersion)
import Import
import Paths_MyApp (version)
getVersionR :: Handler Value
getVersionR = return $ object
[ "version" .= T.pack (showVersion version) ]
I added an import in Application.hs:
import Handler.Version
and a line in routes:
/version VersionR GET
but I am getting the following error when running cabal install:
.../MyApp/dist/build/libHSMyApp-0.1.0.a(Version.o):(.text+0xda5):
undefined reference to `MyAppszm0zi1zi0_PathszuMyApp_version1_closure'
I suspect something is missing in my .cabal file, but I'm not sure what. I added Handler.Version to the exposed-modules section, but am wondering if I need to somehow mention the Paths_* file.
Solved:
I added
Paths_MyApp
to the exposed_modules section of the .cabal file. It now compiles correctly.

Resources