How do I putStrLn a Data.ByteString.Internal.ByteString? - string

I'm learning haskell and decided to try writing some small test programs to get use to Haskell code and using modules. Currently I'm trying to use the first argument to create a password hash using the Cypto.PasswordStore. To test out my program I'm trying to create a hash from the first argument and then print the hash to screen.
import Crypto.PasswordStore
import System.Environment
main = do
args <- getArgs
putStrLn (makePassword (head args) 12)
I'm getting the following error:
testmakePassword.hs:8:19:
Couldn't match expected type `String'
with actual type `IO Data.ByteString.Internal.ByteString'
In the return type of a call of `makePassword'
In the first argument of `putStrLn', namely
`(makePassword (head args) 12)'
In a stmt of a 'do' block: putStrLn (makePassword (head args) 12)
I've been using the following links as references but I am now just trial-erroring to no avail.
http://hackage.haskell.org/packages/archive/bytestring/0.9.0.4/doc/html/Data-ByteString-Internal.html
http://hackage.haskell.org/packages/archive/pwstore-purehaskell/2.1/doc/html/Crypto-PasswordStore.html

You haven't imported ByteString, so it's trying to use the String version of putStrLn.
I've provided toBS for the String->ByteString conversion.
Try
import Crypto.PasswordStore
import System.Environment
import qualified Data.ByteString.Char8 as B
toBS = B.pack
main = do
args <- getArgs
makePassword (toBS (head args)) 12 >>= B.putStrLn

You have to do two things differently. First, makePassword is in IO, so you need to bind the result to a name and then pass the name to the IO function. Secondly, you need to import IO functions from Data.ByteString
import Crypto.PasswordStore
import System.Environment
import qualified Data.ByteString as B
main = do
args <- getArgs
pwd <- makePassword (B.pack $ head args) 12
B.putStrLn pwd
Or, if you won't be using the password result anywhere else, you can use bind to connect the two functions directly:
main = do
args <- getArgs
B.putStrLn =<< makePassword (B.pack $ head args) 12

Related

how to list the functions exported by a Haskell module from an .hs script?

I am aware of this thread and the agreed-upon ghci :browse command, but I am looking for something similar to run from a script.hs file:
Say I have a module that I can import into my script.hs. How do I then view the list of functions I have just gained access to?
What I've settled on for now
Adapting this thread that suggests the now-deprecated ghc-mod command-line program, I am
calling the terminal command ghc -e ':browse <module, e.g. Data.List>'
from my script.hs using Shelly.
My full script:
#!/usr/bin/env runghc
{-# LANGUAGE OverloadedStrings #-}
import Safe (headDef)
import Shelly
import System.Environment (getArgs)
import qualified Data.Text as T
mdl :: IO String
mdl = getArgs >>= return . headDef "Data.List"
runShelly :: String -> IO ()
runShelly mdl = shelly $ silently $ do
out <- run "ghc" ["-e", T.pack (":browse " ++ mdl)]
let lns = T.lines out
liftIO $ mapM_ (putStrLn .T.unpack) $ lns
main :: IO ()
main = mdl >>= runShelly
This way I can pass the module name on the command line as <script> <module> and get back the functions, one per line. It defaults to Data.List if I pass no arguments.
So that's a solution, but surely there must be handier introspection facilities than this?

Using Criterion in Haskell

I am very new to Haskell.
I am trying to use Criterion to get performance data. My Main module is as follows:
module Main where
import SingleThreadedBlockChain
import Data.Time.Clock.System (getSystemTime)
import System.IO (readFile)
import System.TimeIt
import System.Environment ( getArgs )
import Criterion.Main
main :: IO ()
main = do
args <- getArgs
time <- getSystemTime
content <- readFile (args !! 0)
defaultMain [
bench "putStrLn" $ nfIO (putStrLn ("The last block is " ++ show (last (makeBlockChain "" (lines content) 0 (show time)))))
]
I am trying to use the Criterion documentation + things I've seen on StackOverflow to get this working. I'm getting the following error:
Error: none of the specified names matches a benchmark
I thought I would be benchmarking IO. From the examples I've seen, the names don't always match the benchmarks. Could someone explain how the names should relate to the benchmarks?
Criterion's defaultMain does its own cli argument parsing. It uses the first argument to try and match a specific benchmark name to run (in your case you only have "putStrLn"). If you want to do your own argument parsing you can change the arguments before passing to defaultMain like this:
args <- getArgs
withArgs (drop 1 args) $ defaultMain ...
This will hide the first argument from defaultMain so you can use it as you please.

Filename argument in Haskell

How comes that this is working:
module Main where
import System.Environment (getArgs)
import qualified Data.ByteString.Char8 as B
import Data.ByteString.Char8 (ByteString)
type Field = ByteString
type Row = [Field]
type CSV = [Row]
main :: IO ()
main = do
contents <- B.readFile "test.csv"
print (parseCSV contents)
-- used with "./myprogram" to read "test.csv"
But not if I replace "test.csv" with a command-line argument in main:
-- ... same as before ...
main :: IO ()
main = do
contents <- B.readFile $ head getArgs
print (parseCSV contents)
-- used with "./myprogram test.csv" to read "test.csv"
With the latter I get this error at compile time:
csv.hs:20:35: error:
• Couldn't match expected type ‘[FilePath]’
with actual type ‘IO [String]’
• In the first argument of ‘head’, namely ‘getArgs’
In the second argument of ‘($)’, namely ‘head getArgs’
In a stmt of a 'do' block: contents <- B.readFile $ head getArgs
EDIT --
I initially omitted a part of the code, which I thought was not necessary to understand the question. It's corrected now.
Remember that getArgs :: IO [String] is also monadic, so you need to extract it first in the do block before trying to get the head of it:
main :: IO ()
main = do
args <- getArgs -- now `args :: [String]`
contents <- B.readFile (head args)
print (parseCSV contents)

Haskell multiple action types inside do block gives error "Couldn't match expected type `ZMQ z a0'"

I am trying to write a simple program in Haskell which listens over Zero MQ socket and publishes it to websocket connection, below is my code
{-# LANGUAGE OverloadedStrings #-}
import Data.Char (isPunctuation, isSpace)
import Data.Monoid (mappend)
import Data.Text (Text)
import Control.Exception (fromException)
import Control.Monad (forM_, forever)
import Control.Concurrent (MVar, newMVar, modifyMVar_, readMVar)
import Control.Monad.IO.Class (liftIO)
import Control.Monad
import qualified Data.Text as T
import qualified Data.Text.IO as T
import qualified Network.WebSockets as WS
import System.ZMQ3.Monadic
import Data.ByteString.Char8 (pack, unpack)
import Control.Concurrent (threadDelay)
import Data.Text.Encoding
import Data.ByteString.Internal
main :: IO ()
main = do
liftIO $ putStrLn "starting main..."
WS.runServer "0.0.0.0" 9160 $ application
application :: WS.Request -> WS.WebSockets WS.Hybi00 ()
application rq = do
liftIO $ putStrLn "starting..."
WS.acceptRequest rq
sink <- WS.getSink
WS.getVersion >>= liftIO . putStrLn . ("Client version: " ++)
msg <- WS.receiveData
liftIO $ putStrLn $ show $ (msg:: Text)
WS.sendTextData (msg :: Text)
runZMQ $ do
repSocket<- socket Rep
s<-return $bind repSocket "tcp://*:6555"
msg2 <- receive repSocket
let quote = msg2
--msg2 <- WS.receiveData
--liftIO $ putStrLn $ quote
WS.sendTextData $ ("test"::Text)
But compiler fails at statement WS.sendTextData $ ("test"::Text) saying below error
websocket_server.hs:42:17:
Couldn't match expected type `ZMQ z a0'
with actual type `WS.WebSockets p0 ()'
In a stmt of a 'do' block: WS.sendTextData $ ("test" :: Text)
In the second argument of `($)', namely
`do { repSocket <- socket Rep;
s <- return $ bind repSocket "tcp://*:6555";
msg2 <- receive repSocket;
let quote = msg2;
.... }'
In a stmt of a 'do' block:
runZMQ
$ do { repSocket <- socket Rep;
s <- return $ bind repSocket "tcp://*:6555";
msg2 <- receive repSocket;
let quote = msg2;
.... }
I am not sure how to deal with this issue how can I make do block statements return same value when the values cannot be converted into each other?
A simple liftIO should be enough for that call, but I haven't tried.
The trouble is that both the ZMQ and Websockets libraries define a "top level monad" that is not a monad transformer. So there is no provided way to layer the monads. This is poor design on their parts.
My suggestion would be to A) write your own ZMQ transformer or B) use the nonmonadic interface provided by ZMQ at the top level.

Idiomatic way to conditionally process IO in Haskell

I'm writing a little shell script in Haskell which can take an optional argument. However, if the argument is not present, I'd like to get a line from stdin in which to ask for a value.
What would be the idiomatic way to do this in Haskell?
#!/usr/bin/env runhaskell
import Control.Applicative ((<$>))
import Data.Char (toLower)
import IO (hFlush, stdout)
import System.Environment (getArgs)
main :: IO ()
main = do args <- getArgs
-- here should be some sort of branching logic that reads
-- the prompt unless `length args == 1`
name <- lowerCase <$> readPrompt "Gimme arg: "
putStrLn name
lowerCase = map toLower
flushString :: String -> IO ()
flushString s = putStr s >> hFlush stdout
readPrompt :: String -> IO String
readPrompt prompt = flushString prompt >> getLine
Oh, and if there's a way to do it with something from Control.Applicative or Control.Arrow I'd like to know. I've become quite keen on these two modules.
Thanks!
main :: IO ()
main = do args <- getArgs
name <- lowerCase <$> case args of
[arg] -> return arg
_ -> readPrompt "Gimme arg: "
putStrLn name
This doesn't fit your specific use case, but the question title made me think immediately of when from Control.Monad. Straight from the docs:
when :: Monad m => Bool -> m () -> m ()
Conditional execution of monadic expressions.
Example:
main = do args <- getArgs
-- arg <- something like what FUZxxl did..
when (length args == 1) (putStrLn $ "Using command line arg: " ++ arg)
-- continue using arg...
You can also use when's cousin unless in similar fashion.

Resources