I have the following function that produces a random string of characters in multiples of 1024:
import System.Random
rchars :: Int -> [IO Char]
rchars n = map (\_ -> randomRIO ('a', 'z')) [n | n <- [0..n]] -- a wasteful "iteration"-like func
rstr :: Int -> IO String
rstr n = sequence $ rchars (1024 * n)
I want to expose this to the web using Spock, for example:
import Data.Monoid
import Data.Text
import Lib
import Web.Spock.Safe
main :: IO ()
main =
runSpock 8080 $ spockT id $
do get root $
redirect "/data/1"
get ("data" <//> var) $ \n ->
do
str <- rstr n
text ("boo:" <> str <> "!")
but this is incorrect, as the innermost do
-block yields an IO b0
, not the expected type from Spock:
Couldn't match type ‘ActionT IO ()’ with ‘IO b0’
Expected type: Int -> IO b0
Actual type: hvect-0.2.0.0:Data.HVect.HVectElim
'[Int] (ActionT IO ())
The lambda expression ‘\ n -> ...’ has one argument,
but its type ‘hvect-0.2.0.0:Data.HVect.HVectElim
'[Int] (ActionT IO ())’
has none
In the second argument of ‘($)’, namely
‘\ n
-> do { str <- rstr n;
text ("boo:" <> str <> "!") }’
In a stmt of a 'do' block:
get ("data" <//> var)
$ \ n
-> do { str <- rstr n;
text ("boo:" <> str <> "!") }
How can I use my IO
-driven random string function inside the Spock get request handler?
The ActionT
type is an instance of MonadIO
typeclass. That means you can use liftIO
to perform IO actions inside this monad. In your case you seem to need liftIO $ rstr n
instead of plain rstr n
.
This demonstrates what I'm referring to:
import Control.Monad.IO.Class
...
main :: IO ()
main =
runSpock 8080 $ spockT id $
do get root $
redirect "/data/1"
get ("data" <//> var) $ \n ->
do
str <- liftIO $ rstr n
text $ pack str