【发布时间】:2020-07-02 02:34:48
【问题描述】:
我有一些类和它们的实例。该示例显示了一些无意义的类。它们的确切性质并不重要。
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE FlexibleInstances #-}
class Foo a where
foo :: a -> Int
class Bar a where
bar :: a -> String
instance Foo Int where
foo x = x
instance Foo String where
foo x = length x
instance Bar Int where
bar x = show x
instance Bar String where
bar x = x
好的,现在我想创建一些存在类型,将这些类隐藏在某些数据类型外观之后,因此我不必处理约束。 (我知道存在类型被认为是一种反模式,请不要向我解释)。
data TFoo = forall a. Foo a => TFoo a
instance Foo TFoo where
foo (TFoo x) = foo x
data TBar = forall a. Bar a => TBar a
instance Bar TBar where
bar (TBar x) = bar x
显然那里有一些样板。我想把它抽象出来。
{-# LANGUAGE ConstraintKinds #-}
data Obj cls = forall o. (cls o) => Obj o
所以我只有一个,而不是几个存在类型,由一个类型类参数化。到目前为止一切顺利。
现在如何对Obj a 执行操作?显而易见的尝试
op f (Obj a) = f a
因为类型变量可能逃逸而失败。
existential.hs:31:18: error:
• Couldn't match expected type ‘o -> p1’ with actual type ‘p’
because type variable ‘o’ would escape its scope
This (rigid, skolem) type variable is bound by
a pattern with constructor:
Obj :: forall (cls :: * -> Constraint) o. cls o => o -> Obj cls,
in an equation for ‘call’
at existential.hs:31:9-13
• In the expression: f k
In an equation for ‘call’: call f (Obj k) = f k
• Relevant bindings include
k :: o (bound at existential.hs:31:13)
f :: p (bound at existential.hs:31:6)
call :: p -> Obj cls -> p1 (bound at existential.hs:31:1)
|
31 | call f (Obj k) = f k
| ^^^
Failed, no modules loaded.
我有点明白为什么会发生这种情况。但是对于像call foo 和call bar 这样的真正调用,类型变量不会逃逸。我可以说服编译器吗?也许我能以某种方式表达u -> v where v does not mention u 的类型(它真的应该是f 的类型)?如果不是,还有什么其他方法可以处理这种情况?我想我可以使用 TemplateHaskell 生成一些东西,但我仍然无法理解它。
【问题讨论】:
-
您能更具体地说明您要做什么吗?
op是什么? -
你正在做的事情是可能的。您没有向我们展示的代码中某处存在更详细的错误。
-
@luqui 这是我要编译的确切代码,这是唯一的错误。
-
@dfeuer 这是我尝试用子类型探索一个小对象系统(如面向对象编程)。
op,或者更确切地说是flip op,将是一个方法选择器,就像典型 OOP 语言的object . method中的.。我知道这可能不是最好的方法......