Haskell 如果函数';谁的论点?
我正在编写一些数据访问例程,使用持久化。我想用表示JSON的数据类型来定义API,但在持久性方面,我的数据类型是由持久性的模板系统定义的 鉴于我有从json到数据库数据类型的映射,反之亦然,我认为我应该能够编写通用的数据访问例程 在我尝试编写插入函数之前,一切都进展顺利:Haskell 如果函数';谁的论点?,haskell,type-inference,Haskell,Type Inference,我正在编写一些数据访问例程,使用持久化。我想用表示JSON的数据类型来定义API,但在持久性方面,我的数据类型是由持久性的模板系统定义的 鉴于我有从json到数据库数据类型的映射,反之亦然,我认为我应该能够编写通用的数据访问例程 在我尝试编写插入函数之前,一切都进展顺利: standardInsert :: forall d . forall j . (PersistEntityBackend d ~ SqlBackend, PersistEntity d,
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
standardsert::forall d。福尔j。
(persistenitybackend d~SqlBackend、persistenty d、SimpleJsonDataAccessConversion j d)
=>j->DatabaseEnvironmentT(可能(使用id j))
standardInsert json=do
maybeIdGHC将无法推断类型变量d
。您需要通过添加伪参数将其添加到类型签名本身。标准技巧是为这个伪参数使用代理,这意味着调用方不需要给出该类型的实际值
对于GHC=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
从GHC 7.8开始,Data.Proxy
实际上位于base
中。与其指定函数采用Proxy d
,我更喜欢使用pd
参数。在这类代码中,很常见的情况是已经有了与该类型匹配的可用内容,因此可以直接使用预先存在的值,而我更喜欢显式编写Proxy::d
。太棒了,非常感谢!我开始觉得我可能已经有点喜欢类型类了,也许我应该抛弃SimpleJsonDataAccessConversion jd
,只传递一个包含j->d
和d->j
方法的数据结构。不过,我很想知道这是否可行。非常感谢您提供了一个非常清晰的答案。@JohnL显然这是一个风格/品味的问题,因此意见会有所不同,但我更愿意明确地说,传入的值对计算没有影响。@GaneshSittampalam将其编写为代理d
,这有助于使其更清晰。如果您熟悉参数,您很容易就会发现,如果函数类型中没有出现proxy
类型的参数,则不能使用proxy d
类型的参数。