Reputation: 14093
I'm writing some data-access routines, using Persistent. I want my API to be defined in terms of datatypes which represent JSON, but on the persistent side, my datatypes are defined by persistent's templating system.
Given that I have mappings from json to database datatypes, and vice-versa, I thought I should be able to write generalised data access routines.
All was going well until I tried to write the insert function:
standardInsert :: forall d . forall j .
(PersistEntityBackend d ~ SqlBackend, PersistEntity d, SimpleJsonDataAccessConversion j d)
=> j -> DatabaseEnvironmentT (Maybe (WithId j))
standardInsert json = do
maybeId <- runSqlMaybe $ insert db
return $ toApi <$> maybeId
where db = jsonToDataAccess json :: d -- Scoped type variable here.
toApi key = addId key $ dataAccessToJson db
(j
is the type variable for the JSON data type, d
is the type variable for the persistent data type).
This function has two type variables, j
and d
, but only j
can be inferred from the arguments.
In other words, if I call standardInsert jsonValue
, the type variable d
is ambiguous.
I want to call it rather like in C++ - standardInsert<FooJsonType, FooPersistentType>(jsonValue)
.
How do I tell Haskell what d
is? Or am I going about this in completely the wrong way?
Upvotes: 6
Views: 108
Reputation: 29100
GHC won't be able to infer the type variable d
. You need to add it to the type signature itself, by adding a dummy argument. The standard trick is to use a proxy for this dummy argument, which means the caller doesn't need to give an actual value of that type.
You can get Proxy
from the tagged
package for GHC<7.8, or from base
for GHC>=7.8, but for the purposes of the explanation I'll define it explicitly here:
data Proxy a = Proxy
standardInsert :: forall d . forall j .
(PersistEntityBackend d ~ SqlBackend,
PersistEntity d, SimpleJsonDataAccessConversion j d)
=> Proxy d -> j -> DatabaseEnvironmentT (Maybe (WithId j))
standardInsert _ json = do (...)
and then at a call site:
standardInsert (Proxy :: Proxy FooPersistentType) jsonValue
Upvotes: 9