Trying to pass a random string to SHA in Haskell - haskell

I'm trying to pass a random string (which happens to be a number) "4176730.5" to SHA in Haskell to get a larger random string like "2d711642b726b04401627ca9fbac32f5c8530fb1903cc4db02258717921a4881".
I have this code to generate a random number and cast it to a string
num <- randomIO :: IO Float
let x = C.pack (show (num*10000000))
print x
but when I pass it to SHA with
let a = sha256 x
I get the error
Couldn't match expected type ‘Data.ByteString.Lazy.Internal.ByteString’
with actual type ‘C.ByteString’
I've tried casting my number to C.ByteString, but I think there are two types of Bytestring, according to the Haskell compiler.
The full code is:
import Data.Digest.Pure.SHA
import System.Random
import qualified Data.ByteString.Char8 as C
main :: IO ()
main = do
num <- randomIO :: IO Float
let x = C.pack (show (num*10000000))
print x
let a = sha256 x
b = hmacSha256 "key" "some test message"
mapM_ print [showDigest a, showDigest b]
Seeing as how there are apparently two types of Bytestring, and I'm casting to the wrong one, how do I cast my random string correctly?
Further to #Cubic's answer below if I replace
import qualified Data.ByteString.Char8 as C
with
import qualified Data.ByteString.Lazy as C
I just get these errors
Couldn't match type ‘Char’ with ‘GHC.Word.Word8’
Expected type: [GHC.Word.Word8]
Actual type: String
and
Couldn't match expected type ‘C.ByteString’
with actual type ‘[Char]’

The issue is that a ByteString is a sequence of bytes, while a String is a sequence of chars. There are many ways to turn chars into bytes, so you need to specify which encoding you want. Most likely, you want an ASCII or UTF8 encoding. If so, you can use this solution below, which converts strings into "UTF8 bytes" as needed.
import Data.Digest.Pure.SHA
import System.Random
import qualified Data.ByteString.Lazy as C
import qualified Data.ByteString.Lazy.UTF8 as U
main :: IO ()
main = do
num <- randomIO :: IO Float
let x = U.fromString (show (num*10000000))
print x
let a = sha256 x
b = hmacSha256 (U.fromString "key") (U.fromString "some test message")
mapM_ print [showDigest a, showDigest b]

You need Data.ByteString.Lazy, not Data.ByteString.Char8.
In general, you almost never want Data.ByteString.Char8.

Just use the lazy bytestrings as #leftaroundabout mentioned. Your try didn't work because you want to pack from Strings, so you need to import the .Char8 module to achieve that:
import Data.ByteString.Lazy.Char8 as C

Related

Haskell getting value of Either from Get monad

I am a Haskell noob feeling stuck on a rather simple function I am attempting to perform. Ultimately my goal is to read a strict ByteString, use the Get monad with a decoder to retrieve the first Word32 from the ByteString, and perform specific functions where Data.Bits.testBit evaluates to True on various parts of the Word32.
Here is my example code:
import Data.List
import Data.Char
import Data.Function
import System.Random
import Data.Bits
import Data.Either
import Data.Binary.Strict.Get
import System.IO as SIO
import Data.ByteString.Char8 as B
import Data.Word (Word32)
import Data.ByteString.UTF8 as BU
dateTemplate = "YYMMDDhhmmss"
convertFromString :: String -> ByteString
convertFromString s = BU.fromString s
mahDecoder :: Get Word32
mahDecoder = do
first32Bits <- getWord32be
return first32Bits
main :: IO ()
main = do
let a = runGet mahDecoder (convertFromString dateTemplate)
SIO.putStrLn $ show a
-- When I uncomment these lines I get the problem
--case a of
-- Left val -> SIO.putStrLn "Communist!"
-- Right val -> SIO.putStrLn $ "Fascist!"
When I run the runGet function on the decoder and pass my ByteString in main, I can see it returns an Either instance like so:
(Right 1499024717,"DDhhmmss")
When I attempt to case on Left or Right then it fails with the following error:
HSStackOverflowExamp.hs:31:5:
Couldn't match expected type `(Either String Word32, ByteString)'
with actual type `Either t0 t1'
In the pattern: Left val
In a case alternative: Left val -> SIO.putStrLn "Communist!"
In a stmt of a 'do' block:
case a of {
Left val -> SIO.putStrLn "Communist!"
Right val -> SIO.putStrLn $ "Fascist!" }
Any ideas what I am doing wrong here? I get the feeling like I am supposed to read all bytes from the ByteString with the decoder. To be honest I am not entirely sure what the type of a is here. I still have a very limited understanding of Monads and Monad Transformers. I was hoping that I didn't need to master every one of the Haskell dark arts before I could implement even simple use cases for practice. If the answer is to keep reading then I accept that.
The type of a is a tuple where the first item is an Either. Try changing your case statement to this:
case a of
(Left val, _) -> SIO.putStrLn "Communist!"
(Right val, _) -> SIO.putStrLn $ "Fascist!"

I/O Monad and ByteString to Char conversion?

I'm testing some HTTP requests in haskell and have the below methods:
import qualified Data.ByteString.Lazy as LAZ
import Language.Haskell.TH.Ppr
import System.IO
import Data.Word (Word8)
request :: IO LAZ.ByteString
request = do
response <- simpleHttp "https://www.url.com"
return (response)
exampleFunctionOne:: IO LAZ.ByteString -> IO LAZ.ByteString
exampleFunctionOne bytes = do
html <- bytes
let bytesToChars = bytesToString $ LAZ.unpack html
let x = exampleFunctionTwo bytesToChars
bytes
exampleFunctionTwo :: [Char] -> [Char]
exampleFunctionTwo chars = --Do stuff...
main = do
exampleFunctionOe $ request
My questions are:
Is there a more straight forward way to convert the ByteString to [Char]? Currently I've having to convert to perform (ByteString -> Word8) and then (Word8 -> Char)
Am I correct in saying the 'return ()' statement in my request function is simply re-applying the monad context (in this case IO) to the value I've extracted (response <- simpleHttp)? Or does it have an additional purpose?
To answer your first question, note that there's a different "unpack" in Data.ByteString.Lazy.Char8 with the signature you want:
unpack :: ByteString -> String
It's not unusual for people to import both modules:
import qualified Data.ByteString.Lazy as B
import qualified Data.ByteString.Lazy.Char8 as C
and mix and match functions from each.
To answer your second question, yes that's more or less it. For example:
redund = do x <- getLine
y <- return x
z <- return y
u <- return z
return u
is all equivalent to redund = getLine with a bunch of re-wrapping and extracting of pure values into an out of an IO monad.

How to read an array of binary data from a file in haskell?

Trying to read a binary file of Word8, I have the following program:
import qualified Data.Binary as B
type Chars = [B.Word8]
printChars :: Chars -> IO()
printChars cs = mapM_ print cs
main :: IO()
main = do
chars <- B.decodeFile "chars"
printChars chars
When I run it, I get an error:
$ ./test
test: too few bytes. Failed reading at byte position 241
It seems decodeFile expects an infinite list.
How can I tell it to just read as many elements as possible?
Edit:
Here was the code I was looking for: (This works with any type, not just Word8.)
import Prelude hiding ( readFile )
import Data.ByteString.Lazy ( readFile )
import Data.Binary.Get ( isEmpty, runGet )
import qualified Data.Binary as B
type Chars = [B.Word8]
printChars :: Chars -> IO()
printChars cs = mapM_ print cs
-- see http://hackage.haskell.org/package/binary-0.7.1.0/docs/Data-Binary-Get.html
-- function getTrades
getChars = do
e <- isEmpty
if e then return []
else do
c <- B.get
cs <- getChars
return (c:cs)
main :: IO()
main = do
input <- readFile "chars"
printChars $ runGet getChars input
Data.Binary is used to serialize known types in a canonical way (defined by the Binary class instance). In general it isn't intended for unstructured data.
In the case you gave us, you are attempting to deserialize the bytes in a file to an object of type [B.Word8]. If you look in the Data.Binary source code, you can see the following
instance Binary a => Binary [a] where
get = do n <- get :: Get Int
getMany n
which basically means that arrays are stored as follows
[length of array, val1, val2, ....]
so, when you applied the value to the file, it read the first Int in the file (no doubt, a very large number), then attempted to read that number of values.
If you just want to load the file as bytes, you should use Data.ByteString.getContents

Haskell Aeson JSON Library ByteString Issue

I'm having trouble finding a function or workaround to convert a String to Data.ByteString.Lazy.Internal.ByteString
One of the functions in the Aeson Json library is decode and has the following description:
decode :: FromJSON a => bytestring-0.10.0.2:Data.ByteString.Lazy.Internal.ByteString -> Maybe a
I've tried using the pack function in Data.ByteString.Lazy.Char8 but that returns a different ByteString. Any one know how this can be fixed?
The following is the example I'm working on:
import Data.Aeson
import Data.Text
import Control.Applicative
import Control.Monad (mzero)
import qualified Data.ByteString.Lazy.Internal as BLI
import qualified Data.ByteString.Lazy.Char8 as BSL
data Person = Person
{ name :: Text
, age :: Int
} deriving Show
instance FromJSON Person where
parseJSON (Object v) = Person <$>
v .: (pack "name") <*>
v .: (pack "age")
parseJSON _ = mzero
I tried using decode (BSL.pack "{\"name\":\"Joe\",\"age\":12}") :: Maybe Person
and got the following error message:
Couldn't match expected type `bytestring-0.10.0.2:Data.ByteString.Lazy.Internal.ByteString'
with actual type `BSL.ByteString'
In the return type of a call of `BSL.pack'
In the first argument of `decode', namely
`(BSL.pack "{\"name\":\"Joe\",\"age\":12}")'
In the expression:
decode (BSL.pack "{\"name\":\"Joe\",\"age\":12}") :: Maybe Person
Help!
You need to convert Char to Word8 using c2w (in Data.ByteString.Internal)
Data.ByteString.Lazy.pack $ map c2w "abcd"
I wrote out the fully qualified name for pack also to guarantee using the correct one, but you can clean this up in the imports section. When I run
> :t Data.ByteString.Lazy.pack $ map c2w "abcd"
I get ":: Data.ByteString.Lazy.Internal.ByteString"
Remember that Data.ByteString.Lazy represents strings of number values (you can't even run its pack on strings, you need to supply an array of numbers "pack [1, 2, 3, 4]"), so you might actually want to use the char equivalent Data.ByteString.Lazy.Char8.
You can also use for convenience fromString from Data.ByteString.Lazy.UTF8 from utf8-string.
It's a module of functions for the same ByteString type as aeson uses. It relyies on UTF8 as the encoding used in the buffers.

haskell [char] to bytestring

main :: IO ()
main = do
let a = ("teeeeeeeeeeeeest","teeeeeeeeeeeest")
b <- app a
print b
app expects (bytestring,bytestring) not ([char],[char])
how can I convert it?
You can convert Strings to ByteStrings with Data.ByteString.Char8.pack (or the lazy ByteString version thereof) if your String contains only ASCII values or you are interested only in the last eight bits of each Char,
import qualified Data.ByteString.Char8 as C
main :: IO ()
main = do
let a = ("teeeeeeeeeeeeest","teeeeeeeeeeeest")
b <- app $ (\(x,y) -> (C.pack x, C.pack y)) a
print b
If your String contains non-ASCII Chars and you are interested in more than only the last eight bits, you will need some other encoding, like Data.ByteString.UTF8.fromString.
You could try:
import qualified Data.ByteString.Char8 as B --to prevent name clash with Prelude
B.pack "Hello, world"
A lot of useful functions can be found here:
http://www.haskell.org/ghc/docs/latest/html/libraries/bytestring/Data-ByteString-Char8.html
you could also use Data.ByteString.Lazy.Char8
for lazy bytestrings
http://hackage.haskell.org/packages/archive/bytestring/latest/doc/html/Data-ByteString-Lazy-Char8.html#v:pack

Resources