Another newbie question that probably results from me not having grasped Monadic do
in Haskell: I want to write a simple QuickCheck generator for well-formed URIs, using the Text.URI
type from the modern-uri
package. To my understanding, there are two types of monads involved here: MonadThrow
for error handling upon URI construction, and Gen
from QuickCheck.
Here is my attempt to implement the generator. It does not type check:
import qualified Text.URI as URI
uriGen :: Gen URI.URI
uriGen = do
sc <- elements ["https", "http", "ftps", "ftp"]
tld <- elements [".com", ".org", ".edu"]
hostName <- nonEmptySafeTextGen -- (:: Gen Text), a simple generator for printable text.
uri <- do
scheme <- URI.mkScheme sc
host <- URI.mkHost $ (hostName <> "." <> tld)
return $ URI.URI (Just scheme) (Right (URI.Authority Nothing host Nothing)) Nothing [] Nothing
return uri
My understanding is that the outer do
block pertains to the Gen
monad while the inner one handles MonadThrow
. I attempt to unwrap the Text
pieces from their Gen
and then use the unwrapped Text
to build up URI
pieces, unwrap them from their MonadThrow
, then reassemble the entire URI, and finally wrap it in a new Gen
.
However, I get the following type-check error:
• No instance for (MonadThrow Gen)
arising from a use of ‘URI.mkScheme’
• In a stmt of a 'do' block: scheme <- URI.mkScheme sc
In a stmt of a 'do' block:
uri <- do scheme <- URI.mkScheme sc
host <- URI.mkHost $ (hostName <> "." <> tld)
return
$ URI.URI
(Just scheme)
(Right (URI.Authority Nothing host Nothing))
Nothing
[]
Nothing
From the error, I suspect that my intuition about unwrapping and wrapping the URI pieces is wrong. Where do I err? What would be the right intuition?
Thanks very much for your help!