1

在下面的代码中,我对返回值所做的foo只是使用它的Show接口

foo :: String
foo = "asdf"

main = do
    print foo

有没有办法修改类型签名foo来强制执行这一点,禁止人们将字符串视为字符列表,只让他们通过抽象类型类接口访问它?我认为存在类型可能是可能的,但我不知道如何。


我想这样做的原因是因为在 HDBC 数据库库中,所有功能都可以作为IConnection类型类的方法使用。我正在编写创建数据库连接的函数,我想知道它的返回类型是否可以反映抽象接口而不是返回具体的 Sqlite3 Connection

现在我搜索了一下,发现有一个可用的ConnWrapper数据类型,但我仍然无法理解这一切是如何组合在一起的。返回 ConnWrapper 是唯一的方法吗?

4

1 回答 1

7

存在类型确实有可能,但这很可能是个坏主意

使用存在类型的方法是ConnWrapper,就像你说的:

data ConnWrapper = forall conn. IConnection conn => ConnWrapper conn

该类型相对简单:它是一个IConnection字典以及与之兼容的类型的值。如果x :: connconn是 的一个实例IConnection,那么ConnWrapper x :: ConnWrapper。给定y :: ConnWrapper,除了它是IConnection. 所以你可以说case y of ConnWrapper z -> disconnect z,但你不能说case y of ConnWrapper z -> z——没有你可以给它的 Haskell 类型。

(ConnWrapper也是IConnection直接的一个实例,并且由于该类非常简单,这意味着您几乎不需要ConnWrapper直接进行模式匹配。您可以使用disconnect y等等。)

如果您正在制作 API,我强烈建议您按照我上面链接的帖子的内容重新考虑,或者至少理解这种方法。Haskell 中 ExistentialTypes 的许多使用实际上比不存在的方法更复杂。例如,您应该看到为什么data Foo = forall a. Show a => Foo a(几乎)等价于String. 看起来 HDBC 可能打算以这种方式使用,虽然......

于 2013-06-11T01:08:06.403 回答