如何为函数指定类型,它们不在函数的参数中使用?

时间:2014-07-09 21:16:35

标签: haskell type-inference

我正在使用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是持久数据类型的类型变量。)

此函数有两个类型变量jd,但只能从参数中推断出j

换句话说,如果我调用standardInsert jsonValue,则类型变量d不明确。

我想在C ++中调用它 - standardInsert<FooJsonType, FooPersistentType>(jsonValue)

如何告诉Haskell d是什么?或者我是以完全错误的方式解决这个问题?

1 个答案:

答案 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