haskell - 存储和检索某个类型类的对象 - 可能吗?如果是,如何?

标签 haskell typeclass

假设我有一些类型类 Foo 和一些数据类型 FooInstFoo 的实例:

class Foo a where
  foo :: a -> String

data FooInst = FooInst String

instance Foo FooInst where
    foo (FooInst s) = s

现在,我想定义一个数据类型来存储一个对象,该对象的类型在 Foo 类型类中,并且能够从该数据类型中提取该对象并使用它。

我发现的唯一方法是使用 GADTs 和 Rank2Types 语言扩展并像这样定义数据类型:

data Container where
  Container :: { content :: Foo a => a } -> Container

但是,问题是,我不能使用 content 选择器从容器中获取内容:

cont :: Container
cont = Container{content = FooInst "foo"}

main :: IO ()
main = do
  let fi = content cont
  putStrLn $ foo fi

导致编译错误

Cannot use record selector ‘content’ as a function due to escaped type variables
Probable fix: use pattern-matching syntax instead

但是当我将 let ... 行修改为

let Conainer fi = cont

我遇到了一个相当有趣的错误

My brain just exploded
I can't handle pattern bindings for existential or GADT data constructors.
Instead, use a case-expression, or do-notation, to unpack the constructor.

如果我再次尝试修改 let ... 行以使用 case-expression

let fi = case cont of
           Container x -> x

我得到一个不同的错误

Couldn't match expected type ‘t’ with actual type ‘a’
  because type variable ‘a’ would escape its scope
This (rigid, skolem) type variable is bound by
  a pattern with constructor
    Container :: forall a. (Foo a => a) -> Container,
  in a case alternative
  at test.hs:23:14-24

那么,我怎样才能存储一个类型分类的东西并取回它呢?

最佳答案

与:

data Container where
    Container :: {content :: Foo a => a} -> Container

类型类约束甚至没有强制执行。那就是

void :: Container
void = Container {content = 42 :: Int}

类型检查,即使 42::Int 不是 Foo 的实例。

但如果你改为:

data Container where
    Container :: Foo a => {content :: a} -> Container
  1. 您不再需要 Rank2Types 语言扩展。
  2. 强制执行类型类约束;因此上面的 void 示例将不再进行类型检查。
  3. 此外,您可以通过模式匹配在内容上调用 foo(或任何其他带有签名 Foo a => a -> ... 的函数) :

    case cont of Container {content = a} -> foo a
    

关于haskell - 存储和检索某个类型类的对象 - 可能吗?如果是,如何?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38171870/

相关文章:

haskell - 在 Haskell 中将两个类合并/合并为一个类

Haskell:类型类和实例(不在范围内:数据构造函数..)

haskell - 如何在 Haskell 中编写 Data.Vector.Unboxed 实例?

haskell - 默认方法中对幻像类型的类约束的编译错误

haskell - 未找到 System.IO.UTF8(安装 PureScript)

haskell - 读取实例导致解析错误

haskell - 如何在 Haskell 中创建 "kind class",或使用类型族在类型级别创建临时多态性

regex - Haskell 在一次传递中用正则表达式替换多个子字符串

haskell - QuickCheck 如何测试每个 sample 的所有属性

haskell - 使用 typeclass 方法的默认实现来省略参数