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

stu*_*ith 6 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
Run Code Online (Sandbox Code Playgroud)

(j是JSON数据类型d的类型变量,是持久数据类型的类型变量).

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

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

我想在C++中称它为 - standardInsert<FooJsonType, FooPersistentType>(jsonValue).

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

GS *_*ica 9

GHC将无法推断出类型变量d.您需要通过添加伪参数将其添加到类型签名本身.标准技巧是为此伪参数使用代理,这意味着调用者不需要提供该类型的实际值.

您可以ProxytaggedGHC <7.8或baseGHC> = 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 (...)
Run Code Online (Sandbox Code Playgroud)

然后在呼叫站点:

standardInsert (Proxy :: Proxy FooPersistentType) jsonValue
Run Code Online (Sandbox Code Playgroud)

  • 从GHC 7.8开始,`Data.Proxy`实际上是在'base`中. (2认同)