I'm using Lucid in a small Scotty project.
In below program:
p_ "hello world"
I want to run some string functions such as:
p_ (reverse "hello world")
Of course I got a type error.
Could anyone help how I can make this work?
You can do the fromString :: IsString s => String -> s conversion yourself, which is basically what OverloadedStrings [ghc-doc] does for you. For example:
import Data.String(fromString)
p_ (fromString (reverse "hello world"))
If you enable OverloadedStrings, then you could say that the compiler implicitly uses a fromString for each string literal, here we will make the conversion ourself explicitly.
Given that here "hello world" is (likely) a Text, you can do the reversing in the Text world:
{-# OverloadedStrings #-}
import qualified Data.Text as T
p_ (T.reverse "hello world")
Related
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.
I'm trying out Scotty for the first time and I can't seem to get past making my GET request. The Response is returned as type
IO (Response bytestring-0.10.8.1:Data.ByteString.Lazy.Internal.ByteString)
I know I need to convert it to a type that can be output by Scotty but I can't figure out how to do that.
My full code is :
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE OverloadedStrings #-}
module Main where
import Control.Lens
import Control.Monad.IO.Class
import Data.Aeson (FromJSON, ToJSON, Value, decode,
encode)
import Data.Map as Map
import GHC.Generics
import Lib
import Network.Wreq as Wreq
import Web.Scotty as Scotty
main :: IO ()
main =
scotty 3000 $
Scotty.get "/" $ do
-- html "Hello World!"
Wreq.get"https://www.metaweather.com/api/location/search/?query=New%20York"
I tried using LiftIO but that is still giving me a Type Error. I wanted to know how exactly I should convert my Response so that I can display it in the front-end just like I displayed my initial "Hello World" with html.
If you are just looking for a quick proof of concept and aren't worried about erroneous responses, you could use the responseBody lens and send the lazy byte string to raw instead of html:
main :: IO ()
main =
scotty 3000 $
Scotty.get "/" $ do
r <- liftIO $ Wreq.get "https://www.metaweather.com/api/location/search/?query=New%20York"
raw (r ^. responseBody)
Trying to make a yesod app (without stack, and yesod init) and when ever I compile it I run into this monad error. I know these issues are common, but I've never seen anyone ask this question with these specific types (i.e. HandlerT and IO String). Here's all my code, so I think it should be easy enough for someone to test this. Also I'm using GHC 7.10.3, which is a little older, but I don't think my issue has anything to do with the compiler version.
$ ghc --version
The Glorious Glasgow Haskell Compilation System, version 7.10.3
Here's the compiler error message:
$ ghc -o yesod_test yesod_monad_test.hs
[1 of 1] Compiling Main ( yesod_monad_test.hs, yesod_monad_test.o )
yesod_monad_test.hs:25:15:
Couldn't match expected type `HandlerT HelloWorld IO Text'
with actual type `IO String'
In a stmt of a 'do' block: snippet <- readFile temp
In the expression:
do { let temp = "posts/" ++ title ++ ".html";
snippet <- readFile temp;
defaultLayout
((asWidgetT . toWidget) (toHtml (preEscapedText snippet))) }
And here's my code.
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE ViewPatterns #-}
import Yesod
import Network.Wai (pathInfo, rawPathInfo, requestMethod, responseLBS)
import Data.Text (Text)
import Text.Blaze (preEscapedText)
import Control.Exception (IOException, try)
import Control.Monad (when)
data HelloWorld = HelloWorld
mkYesod "HelloWorld" [parseRoutes|
/post/#String PostR GET
|]
instance Yesod HelloWorld
getPostR :: String -> Handler Html
getPostR title = do
let temp = "posts/" ++ title ++ ".html"
snippet <- readFile temp
defaultLayout [whamlet|#{preEscapedText snippet}|]
main :: IO ()
main = warp 3000 HelloWorld
I'm surprised that this code doesn't work, since I believe I'm following the tutorial (http://www.yesodweb.com/book/routing-and-handlers#routing-and-handlers_overlap_checking) pretty closely, though I'm using Strings over the Text type.
Thank you.
#Alec's answer was basically correct. Thanks!
Basically, #amalloy is telling you to replace snippet <- readFile temp with snippet <- liftIO $ readFile temp.
I am new to Haskell, and am working on testing JSON serialization. Here is what the test case looks like:
{-# LANGUAGE OverloadedStrings #-}
module WetlandsTest where
import Control.Exception (evaluate)
import Test.Hspec
import Wetlands
main :: IO ()
main = hspec $ do
describe "wetlands" $ do
describe "spotting" $ do
it "returns a json encoded spotting" $ do
let record = spotting "Snowy Egret" "California" "low tide"
record `shouldBe` "{\"bird\":\"Snowy Eget\",\"state\":\"California\",\"meta\":\"low tide\"}"
Is there a way to write that in a more readable way? Maybe something along the lines of:
record `shouldBe` """
{"bird":"Snowy Eget","city":"California","meta":"low tide"}
"""
This isn't necessarily a multiline string, but if you prettified the JSON then it would be. Just wondering in general.
Just use the quasi-quotes extension and the string-qq package:
{-# LANGUAGE QuasiQuotes #-}
import Data.String.QQ
someString :: String
someString = [s|
This is"
some string with "" quotes and stuff"!
|]
With output:
*Main> someString
"This is\"\nsome string with \"\" quotes and stuff\"!\n"
I got sick of unpacking Data.Text instances all the time before printing them out for debugging and thought to just use Text.Printf for that. Unfortunately, I couldn't make it work:
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
import Data.Text
import Text.Printf
--instance PrintfArg Text where
-- toUPrintf = toUPrintf . unpack
main :: IO ()
main = do
let input :: Text = "abc"
printf "Input: %s\n" input
The error:
src/Main.hs:12:3:
No instance for (PrintfArg Text)
arising from a use of `printf'
Possible fix: add an instance declaration for (PrintfArg Text)
In a stmt of a 'do' block: printf "Input: %s" input
In the expression:
do { let input :: Text = "abc";
printf "Input: %s" input }
In an equation for `main':
main
= do { let input :: Text = ...;
printf "Input: %s" input }
After uncommenting the instance declaration:
src/Main.hs:7:7:
`toUPrintf' is not a (visible) method of class `PrintfArg'
src/Main.hs:7:19: Not in scope: `toUPrintf'
Any ideas?
EDITED
As suggested, tried TH, still no go:
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell #-}
import Data.Text
import Language.Haskell.TH
import Text.Printf
runQ [d| instance PrintfArg Text where toUPrintf = toUPrintf . unpack|]
main :: IO ()
main = do
let input :: Text = "abc"
printf "Input: %s\n" input
Error:
src/Main.hs:9:40:
'toUPrintf' is not a (visible) method of class 'PrintfArg'
src/Main.hs:9:52: Not in scope: 'toUPrintf'
Help! It's amazing this doesn't work out of the box given all the advice to use Data.Text by default.
WARNING: text-format is unmaintained, no response from the author in 2 years. See other answers.
I'd look at the text-format package: it is similar to Text.Printf, but specifically designed for Data.Text.Lazy.
There are a few other advantages of text-format over Text.Printf:
The Buildable class is exposed, so it can be extended to support new parameter types.
It uses a simpler approach to varargs, which sidesteps problems one has in Text.Printf with accessing the return value.
It should be much faster, for several reasons:
it never converts to the inefficient String representation;
it doesn't build intermediate datatypes, unlike UPrintf in Text.Printf;
it uses the double-conversion package for rendering Double and Float, which is about 30 times faster than Prelude's methods.
Since this question was asked, the base and text libraries have been updated to support this. If you have base >= 4.7.0.0 and text >= 1.2.2.0, then the OP's MWE actually works:
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
import Data.Text
import Text.Printf
main :: IO ()
main = do
let input :: Text = "abc"
printf "Input: %s\n" input
Output:
$ ghci
GHCi, version 8.2.2: http://www.haskell.org/ghc/ :? for help
Prelude> :l test.hs
[1 of 1] Compiling Main ( test.hs, interpreted )
Ok, one module loaded.
*Main> main
Input: abc
*Main>
Leaving GHCi.
From the documentation:
The HPrintfType class provides the variable argument magic for hPrintf. Its implementation is intentionally not visible from this module.
While you could use TH to generate HPrintfType instances (because TH ignores export restrictions) the easiest solution is probably a printf' type function:
printt :: PrintType r => Text -> r
printt = printf . Data.Text.unpack
Another package worth checking out: formatting
Combinator-based type-safe formatting (like printf() or FORMAT) for Text.
Example:
format ("Person's name is " % text % ", age is " % hex) "Dave" 54