我正在使用Persistent编写一些数据访问例程。我希望我的API可以用代表JSON的数据类型来定义,但是在持久性方面,我的数据类型是由持久化的模板系统定义的。
鉴于我有从json到数据库数据类型的映射,反之亦然,我认为我应该能够编写通用数据访问例程。
一切顺利,直到我尝试编写插入函数:
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
是JSON数据类型的类型变量,d
是持久数据类型的类型变量。)
此函数有两个类型变量j
和d
,但只能从参数中推断出j
。
换句话说,如果我调用standardInsert jsonValue
,则类型变量d
不明确。
我想在C ++中调用它 - standardInsert<FooJsonType, FooPersistentType>(jsonValue)
。
如何告诉Haskell d
是什么?或者我是以完全错误的方式解决这个问题?
答案 0 :(得分:9)
GHC将无法推断类型变量d
。您需要通过添加伪参数将其添加到类型签名本身。标准技巧是为这个伪参数使用代理,这意味着调用者不需要提供该类型的实际值。
您可以从GHC&lt; 7.8的tagged
包中获取Proxy
,或者从base
获取GHC&gt; = 7.8,但出于解释的目的,我将明确定义这里:
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 (...)
然后在呼叫站点:
standardInsert (Proxy :: Proxy FooPersistentType) jsonValue