Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 没有类型变量约束的typeclass中的值_Haskell_Types_Typeclass - Fatal编程技术网

Haskell 没有类型变量约束的typeclass中的值

Haskell 没有类型变量约束的typeclass中的值,haskell,types,typeclass,Haskell,Types,Typeclass,我正在使用Happstack开发一个Web应用程序,我正在编写一些代码来将我的类型存储在MongoDB中。我想通过将代码放入一个typeclass来缩短代码,这样我就可以使用相同的代码来读写不同类型的数据库。大概是这样的: class DatabaseType a where toDoc :: a -> Document fromDoc :: Document -> a saveCollection :: Text

我正在使用Happstack开发一个Web应用程序,我正在编写一些代码来将我的类型存储在MongoDB中。我想通过将代码放入一个typeclass来缩短代码,这样我就可以使用相同的代码来读写不同类型的数据库。大概是这样的:

class DatabaseType a where
    toDoc           :: a -> Document
    fromDoc         :: Document -> a
    saveCollection  :: Text
    getFromDatabase :: (MonadIO m) => Pipe -> Text -> Value -> m a
    getFromDatabase pipe field value = ...
    ...
现在这里的问题是
saveCollection
,因为它不使用任何类型变量,GHC不会让它编译,但是它对数据库函数(如
getFromDatabase
)非常重要,以便它们知道保存到哪个集合


问题是,如何在类型类中有一个不被类型变量绑定的值。

您必须添加类型变量。最简单的方法是使用代理:

  saveCollection :: proxy a -> Text
  -- Note the `proxy` is lower case

instance DatabaseType MyDB where
  saveCollection _ = "MyDB"
现在要使用它,您可能需要执行以下操作:

import Data.Proxy

foo = saveCollection (Proxy :: Proxy MyDB)
在方法声明中使用小写的原因是方便:如果调用站点上碰巧有一个值,则可以使用类型正确的任何值,而不是
Proxy MyDB


在某些情况下,标准代理技术可能导致有问题的共享丢失。这是因为函数调用的结果通常不会被记忆。在这种情况下,可以使用标记类型<代码>数据。标记的定义

newtype Tagged s b = Tagged {unTagged :: b}
标记类型比代理更难使用,除非您使用部分类型签名或显式类型应用程序,这是GHC最近添加的两个特性。如果你愿意,你可以写

saveCollection :: Tagged a Text
那么在这个例子中,

saveCollection = Tagged "Hi there."
直接使用它将需要以下内容

unTagged (saveCollection :: Tagged MyDB Text)
unTagged (saveCollection@MyDB)
或者,对于部分类型签名

unTagged (saveCollection :: Tagged MyDB _)
或者使用显式类型应用程序

unTagged (saveCollection :: Tagged MyDB Text)
unTagged (saveCollection@MyDB)

由于这种尴尬,标记的
包提供了在基于代理的表示和标记的表示之间转换的功能。

这确实是惯用的解决方案。(+1)尽管如此,我从未完全相信代理a的使用,即使这已经变得非常流行。我会考虑通过例如<代码> [a]代码>而不是<代码>代理A//>来混淆:如果预期值是无关的,并且只有类型是重要的,我宁愿通过一个明确的代码>代理A/<代码>。希望GHC 8和显式类型args能够清除代理。@chi,我通常同意。但是,可以非常方便地使用单例作为代理。如果我有
assoc::Natty x->Natty y->proxy z->(x:+y):+z:~:x:+(y:+z)
并且我有表示三个自然数的单例,我可以将它们传入,而不必首先将第三个转换为代理。