简体   繁体   中英

LiftIO, do block, and syntax

I'm getting to grips with writing an API in Haskell using Scotty. My files are provided below. My questions are:

  1. 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?

  2. 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.

  3. 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM