我如何表达容器的概念,以实现某些透明属性"?例如,考虑容器类型v
,Show a
暗示Show (v a)
。
用例是我想要一个函数,其中被调用者决定使用哪个容器,但保证容器在许多类型类约束方面表现良好。
这是我想到的一个(非工作)例子:
mapUnknown :: (forall v. (Functor v, (forall n. Num n => Num (v n)) => v b -> a))
-> [b] -> [a]
这个想法是你传入一个函数,它必须能够处理任何容器类型v
。保证v
是Functor
,Num b
隐含Num (v b)
。如果您传入的b
不是Num
,则会忽略该规则。
这可能吗?
注意:
以下不起作用:
class Container c a where
foo :: c a -> [a]
instance forall a c. (Container c a, Show a) => Show (c a) where
show _ = "whatever"
f :: (Container c a, Show a) => c a -> String
f as =
show as
这是因为我们可以定义实例Container V a
和Show (V a)
。然后,GHC无法确定是使用show
定义的Container
还是Show (V a)
定义的展示。我们不想定义新的show
函数,我们只想在容器的类型已知时断言它存在。
答案 0 :(得分:1)
好吧,如果我理解正确,你想创建一个类,让我们说NumToNum
,这样两个实例NumToNum v
和Num n
编译器就可以推断出那里是Num (v n)
的一个实例。以下是如何实现这一目标。
这里的关键是创建一个类型,比如NumI :: * -> *
,这样就不会有NumI n
类型的任何值,除非n
属于类{{1} }}。严格来说,这是不可能的,因为Haskell中的任何类型都有人居住(至少Num
)。但是,如果你避免明确地将实现方法标记为(_|_)
并深入研究深度递归,那么你就可以相对安全了:
undefined
因此,如果data NumI n where NumI :: Num n => NumI n
不属于n
类,则仍然存在Num
类型的值undefined
,但其他情况并不多。
当然,您需要Num n
分机。
现在,可以用这种方式定义上述类:
GADTs
有了这些,您可以通过模式匹配获得class NumToNum v where numToNum :: Num n => NumI (v n)
实例:
Num (v n)
由于构造函数case (numToNum :: NumI (v n)) of NumI => do_something
的类型签名,do_something
已经了解Num (v n)
实例。
声明NumI
类的实例很简单,您只需说明
NumToNum