So I am trying to use pipes and Network.Pcap together but I am running into a bug with Data.ByteString types and Network.Pcap bytestring types.
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RankNTypes #-}
import Network.Pcap
import Pipes
import Data.ByteString
--import Data.ByteString.Lazy
getPacket :: (MonadIO m) => PcapHandle -> Producer' (PktHdr, ByteString) m ()
getPacket handle = do
x <- liftIO $ nextBS handle
yield x
main = return ()
As you can see from the comment it isnt a problem of if the bytestring is lazy or strict because i tried both. This is the error:
PCAP.hs:12:15:
Couldn't match type `bytestring-0.10.0.2:Data.ByteString.Internal.ByteString'
with `ByteString'
Expected type: (PktHdr, ByteString)
Actual type: (PktHdr,
bytestring-0.10.0.2:Data.ByteString.Internal.ByteString)
In the first argument of `yield', namely `x'
In a stmt of a 'do' block: yield x
In the expression:
do { x <- liftIO $ nextBS handle;
yield x }
What is wrong with my bytestring types?
As #Michael said, you appear to have two versions of the bytestring package installed. This is apparent from the error, any time you see a package version in the type error (bytestring-0.10.0.2:Data.ByteString.Internal.ByteString) it is a good bet.
So, use sandboxes to avoid this issue in normal workflow (when possible) and unregister (ghc-pkg unregister bytestring-something-something, based on ghc-pkg list) one of the bytestring packages then re-install anything that was depending on the excess package.
Related
I have a Lift instance that works with template-haskell 2.14, but won't compile with later versions. Can someone explain what changes are needed?
{-# LANGUAGE FlexibleInstances, TemplateHaskell #-}
module LiftBS where
import Data.ByteString as B (ByteString, length, unpack)
import Data.ByteString.Unsafe (unsafePackAddressLen)
import Language.Haskell.TH (runIO, litE, stringPrimL)
import Language.Haskell.TH.Lift (Lift(lift))
instance Lift (IO B.ByteString) where
lift bsio = do
bs <- runIO bsio
[|unsafePackAddressLen $(lift (B.length bs)) $(litE (stringPrimL (B.unpack bs))) :: IO ByteString|]
That's a sketchy instance of Lift. It's really not what Lift is for. It isn't an accident that the new type of lift rules out compile-time side effects. Lift is for serializing data structures, which this isn't even doing conceptually. If this were serializing the data structure passed to it, it would be splicing in a representation of the IO action. This is executing an action and serializing the result of that action. That's just not what someone unfamiliar with this code is going to expect to happen.
Also, all the work you're putting in to serialize the ByteString as its components hasn't been necessary since bytestring-0.11.2.0, when it got its own Lift instance.
But the real thing to do here is just write a function that does what you want:
atCompileTime :: Lift a => IO a -> Q Exp
atCompileTime act = do
x <- runIO act
[| pure x |]
It's not a Lift instance, so it can have a type that allows it to do what you want. It's not a Lift instance, so it can have a name that explains what it's actually doing. And as a bonus, it will work across a wide range of versions of template haskell.
I am having a type issue with Haskell, the program below throws the compile time error:
Couldn't match expected type ‘bytestring-0.10.8.2:Data.ByteString.Lazy.Internal.ByteString’ with actual type ‘Text’
Program is:
{-# LANGUAGE OverloadedStrings #-}
module Main where
...
import Control.Concurrent (MVar, newMVar, modifyMVar_, modifyMVar, readMVar)
import qualified Data.Text as T
import qualified Data.Text.IO as T
import qualified Network.WebSockets as WS
import Data.Map (Map)
import Data.Aeson (decode)
...
application :: MVar ServerState -> WS.ServerApp
application state pending = do
conn <- WS.acceptRequest pending
msg <- WS.receiveData conn
-- EITHER this line can be included
T.putStrLn msg
-- OR these two lines, but not both
decodedObject <- return (decode msg :: Maybe (Map String Int))
print decodedObject
...
It seems to me that the basic issue is that putStrLn expects Text whereas decode expects Bytetring.
What I don't get is why I can run this section of the code:
T.putStrLn msg
Or I can run this section of the code:
decodedObject <- return (decode msg :: Maybe (Map String Int))
print decodedObject
But not both together.
What is the proper way to resolve this issue in the program?
I guess this is something like Type Coercion, or Type Inference, or what would be Casting in other languages. The problem is I don't know how to phrase the problem clearly enough to look it up.
It's as if msg can be one of a number of Types, but as soon as it is forced to be one Type, it can't then be another...
I'm also not sure if this overlaps with Overloaded strings. I have the pragma and am compiling with -XOverloadedStrings
I'm quite a newbie, so hope this is a reasonable question.
Any advice gratefully received! Thanks
This is because WS.receiveData is polymorphic on its return type:
receiveData :: WebSocketsData a => Connection -> IO a
it only needs to be WebSocketsData a instance, which both Text and ByteString are. So the compiler just infers the type.
I suggest you just assume it's a ByteString, and convert in Text upon the putStrLn usage.
Thanks to everyone for their advice. My final understanding is that any value in Haskell can be polymorphic until you force it to settle on a type, at which point it can't be any other type (stupid, but I hadn't seen a clear example of that before).
In my example, WS.receiveData returns polymorphic IO a where a is an instance of class WebsocketData which itself is parameterised by a type which can be either Text or Bytestring.
Aeson decode expects a (lazy) Bytestring. Assuming that we settle on (lazy) Bytestring for our a, this means the first line that I mentioned before needs to become:
T.putStrLn $ toStrict $ decodeUtf8 msg
to convert the lazy ByteString to a strict Text. I can do this so long as I know the incoming websocket message is UTF8 encoded.
I may have got some wording wrong there, but think that's basically it.
I'm getting to grips with writing an API in Haskell using Scotty. My files are provided below. My questions are:
In the routes definition, I'm extracting from liftIO whatsTheTime in a do block. This works, but it seems verbose. Is there a nicer syntax?
In the whatsTheTime definition, I'm needing to do fromString. I'd have thought OverloadedString would take care of that, but that's not the case. I'd really appreciate it if somebody pointed out why it doesn't work without fromString.
In a stack project, if I need a directive like OverloadedStrings, do I need to include it every file that needs it, or just at the top of the main entrypoint?
Api.hs:
{-# LANGUAGE OverloadedStrings #-}
module Api
( whatsTheTime
) where
import Data.Time (getCurrentTime)
import Web.Scotty
import Data.String
whatsTheTime :: IO (ActionM ())
whatsTheTime = do
time <- getCurrentTime
return $ text $ fromString ("The time is now " ++ show time)
Main.hs:
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE DeriveGeneric #-}
module Main where
import Api
import Web.Scotty
import Control.Monad.IO.Class
routes = do
get "/" $ do
res <- liftIO whatsTheTime
res
main :: IO ()
main = do
putStrLn "Starting server..."
scotty 3000 routes
(1) This:
do
res <- liftIO whatsTheTime
res
Desugars to this:
liftIO whatsTheTime >>= \ res -> res
If you look at the type of \ m -> m >>= id:
(Monad m) => m (m a) -> m a
That’s exactly the type of join (Hoogle), so you can use:
get "/" $ join $ liftIO whatsTheTime
join is a common idiom for “execute this action which returns an action, and also execute the returned action”.
(2) OverloadedStrings is for overloading of string literals. You have an overloaded literal "The time is now ", but you constrain it to be of type String by using it as an operand of (++) with a String (the result of show time). You can pack the result of show time as a Text instead using fromString or Data.Text.pack:
import Data.Monoid ((<>))
import qualified Data.Text as Text
-- ...
return $ text $ "The time is now " <> Text.pack (show time)
(3) LANGUAGE pragmas operate per file; as #mgsloan notes, you can add OverloadedStrings to the default-extensions: field of your library or executable in your .cabal file.
Trying to make a HTTP request, I got the error:
{-# LANGUAGE OverloadedStrings #-}
import Network.HTTP.Conduit -- the main module
-- The streaming interface uses conduits
import Data.Conduit
import Data.Conduit.Binary (sinkFile)
import qualified Data.ByteString.Lazy as L
import Control.Monad.IO.Class (liftIO)
main :: IO ()
main = do
simpleHttp "http://www.example.com/foo.txt" >>= L.writeFile "foo.txt"
The error is:
Couldn't match type `L.ByteString'
with `bytestring-0.10.0.2:Data.ByteString.Lazy.Internal.ByteString'
Expected type: bytestring-0.10.0.2:Data.ByteString.Lazy.Internal.ByteString
-> IO ()
Actual type: L.ByteString -> IO ()
In the return type of a call of `L.writeFile'
In the second argument of `(>>=)', namely `L.writeFile "foo.txt"'
In a stmt of a 'do' block:
simpleHttp "http://www.example.com/foo.txt"
>>= L.writeFile "foo.txt"
I can't figure out how to solve it because the text of the error doesn't really make sense.
You have two conflicting versions on bytestring package. Try ghc-pkg list bytestring. I'd suggest you to cabalize your code and use cabal sandbox.
See also "Couldn't match expected type with actual type" error when using Codec.BMP
BTW, the error message should be better in ghc-7.8, see https://ghc.haskell.org/trac/ghc/ticket/8278
Using Parsec 3.1, it is possible to parse several types of inputs:
[Char] with Text.Parsec.String
Data.ByteString with Text.Parsec.ByteString
Data.ByteString.Lazy with Text.Parsec.ByteString.Lazy
I don't see anything for the Data.Text module. I want to parse Unicode content without suffering from the String inefficiencies. So I've created the following module based on the Text.Parsec.ByteString module:
{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
module Text.Parsec.Text
( Parser, GenParser
) where
import Text.Parsec.Prim
import qualified Data.Text as T
instance (Monad m) => Stream T.Text m Char where
uncons = return . T.uncons
type Parser = Parsec T.Text ()
type GenParser t st = Parsec T.Text st
Does it make sense to do so?
It this compatible with the rest of the Parsec API?
Additional comments:
I had to add {-# LANGUAGE NoMonomorphismRestriction #-} pragma in my parse modules to make it work.
Parsing Text is one thing, building an AST with Text is another thing. I will also need to pack my String before return:
module TestText where
import Data.Text as T
import Text.Parsec
import Text.Parsec.Prim
import Text.Parsec.Text
input = T.pack "xxxxxxxxxxxxxxyyyyxxxxxxxxxp"
parser = do
x1 <- many1 (char 'x')
y <- many1 (char 'y')
x2 <- many1 (char 'x')
return (T.pack x1, T.pack y, T.pack x2)
test = runParser parser () "test" input
Since Parsec 3.1.2 support of Data.Text is built-in!
See http://hackage.haskell.org/package/parsec-3.1.2
If you are stuck with older version, the code snippets in other answers are helpful, too.
That looks like exactly what you need to do.
It should be compatible with the rest of Parsec, include the Parsec.Char parsers.
If you're using Cabal to build your program, please put an upper bound of parsec-3.1 in your package description, in case the maintainer decides to include that instance in a future version of Parsec.
I added a function parseFromUtf8File to help reading UTF-8 encoded files in an efficient fashion. Works flawlessly with umlaut characters. Function type matches parseFromFile from Text.Parsec.ByteString. This version uses strict ByteStrings.
-- A derivate work from
-- http://stackoverflow.com/questions/4064532/using-parsec-with-data-text
{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
module Text.Parsec.Text
( Parser, GenParser, parseFromUtf8File
) where
import Text.Parsec.Prim
import qualified Data.Text as T
import qualified Data.ByteString as B
import Data.Text.Encoding
import Text.Parsec.Error
instance (Monad m) => Stream T.Text m Char where
uncons = return . T.uncons
type Parser = Parsec T.Text ()
type GenParser t st = Parsec T.Text st
-- | #parseFromUtf8File p filePath# runs a strict bytestring parser
-- #p# on the input read from #filePath# using
-- 'ByteString.readFile'. Returns either a 'ParseError' ('Left') or a
-- value of type #a# ('Right').
--
-- > main = do{ result <- parseFromFile numbers "digits.txt"
-- > ; case result of
-- > Left err -> print err
-- > Right xs -> print (sum xs)
-- > }
parseFromUtf8File :: Parser a -> String -> IO (Either ParseError a)
parseFromUtf8File p fname = do
raw <- B.readFile fname
let input = decodeUtf8 raw
return (runP p () fname input)