I'm using a 3rd party library which has the following types:
data ServicesRequest req contentType res accept = ServicesRequest
{ rMethod :: NH.Method
, rUrlPath :: [BCL.ByteString]
, rParams :: Params
, rAuthTypes :: [P.TypeRep]
}
I'm trying to extract the req
from a list of ServicesRequest
(serviceRequests), similar to this:
let reqs = map (\(ServicesRequest req contentType res accept) -> req) serviceRequests
Unfortunately, this produces a list of NH.Method
's, the first constructor to ServiceRequest.
I've tried different variations to get the `req', but they all give 'parse error in pattern':
let reqs = map (\(ServicesRequest{} req contentType res accept) -> req) serviceRequests
let reqs = map (\((ServicesRequest _ _ _ _) req contentType res accept) -> req) serviceRequests
How can I pattern match on the req
without it being confused as rMethod constructor?
I'm trying to extract the
req
from a list ofServicesRequest
There are no req
s in a ServicesRequest
, so this isn't possible.
Is it possible to pattern match a type?
By default, there's no pattern matching at the type level. You can certainly write types that ensure that the req
type is the same one as in a ServicesRequest
-- just use the same name in both places you want it. For example:
constrainedId :: ServicesRequest req contentType res accept -> req -> req
constrainedId _ = id
Such restricted types can be useful. Check out ScopedTypeVariables
if you need to annotate types inside the body of your function with a req
from the top-level type annotation.
For more advanced uses, type families offer something that looks a bit like type-level pattern matching. For example:
type family ReqFromSR a where
ReqFromSR (ServicesRequest req contentType res accept) = req
You could then write approximately the same type for constrainedId
in a slightly more compact form:
constrainedId :: sr -> ReqFromSR sr -> ReqFromSR sr
-- OR
constrainedId :: ReqFromSR sr ~ req => sr -> req -> req
constrainedId _ = id