想象一下,我们有一个使用库的Haskell程序。该程序从其依赖关系中为类型T提供了一个类型类TC实例。在同一个库的下一个版本中,库作者为类型T提供了另一个类型类TC的实例。相同类型的相同类型的两个实例
我们想要使用两个类型类实例。我们该怎么做?
P.S.新型解决方案将无法正常工作。这两个实例都驻留在我们无法控制的库中。
P.P.S.我没有真实代码的例子。这是一个理论问题。我只想了解类型类如何与库可组合性相结合。
想象一下,我们有一个使用库的Haskell程序。该程序从其依赖关系中为类型T提供了一个类型类TC实例。在同一个库的下一个版本中,库作者为类型T提供了另一个类型类TC的实例。相同类型的相同类型的两个实例
我们想要使用两个类型类实例。我们该怎么做?
P.S.新型解决方案将无法正常工作。这两个实例都驻留在我们无法控制的库中。
P.P.S.我没有真实代码的例子。这是一个理论问题。我只想了解类型类如何与库可组合性相结合。
- A型可以不被声明为一个特定的类比在程序再次的一个实例。
所以在标准的Haskell中是不可能的。
我不知道任何GHC扩展可以让你在GHC中做到这一点。
这是(一个?)为什么孤儿实例(定义与类型和类型类型不同的模块中的实例)通常被认为是一个坏主意。
我可以肯定地说,使用Cabal你只能依赖同一个库的单一版本。
尽管您可以至少将实例替代版本的源代码复制粘贴到项目中,但您仍然只能在每个模块中导入其中的一个。如果您将冲突的实例导入到模块中,您会遇到不可判定的实例问题,因此您将没有实用的解决方案。
说实话,我无法想象为什么人们可能想要为同一个库发出的相同类型拥有不同的同一类的实例。这似乎非常不切实际。虽然我猜测什么可以帮助你处理你的情况,但有两个具有相关实例的类型类型:一个来自当前版本的库,另一个来自旧版本的重命名源代码副本。
一般来说,对于相同类型的多类型实例是不可能的。然而,如果一个类型是在不同的包中定义的,或者是同一个包的老版本,ghc会认为它是一个不同的类型。所以你理论上可以用foo-1.1
定义Foo
及其实例,foo-1.2
定义Foo
及其实例,并将它们一起使用。
但是,在实践中这不会很好。函数只能使用一种类型或另一种类型。当你编写一个在Foo
上运行的函数时,它将只在一个特定的Foo
上运行,而不是两者。基本上你有两个完全分开的,无可争辩的类型。这将是尴尬的使用,完全分开将是多么尴尬,将建设。
与依赖关系树上的相同包的不同版本链接现在不可能,因为它导致dependency conflict。
但是,这个将在GHC status update video所述的将来有可能,只要它们在同一个库中我只能使用一个版本。
如果您想要更好的灵活性和可组合性,然后将类型类作为记录进行指定。 RankNTypes
可能是必要的。
例如,这里是你如何可以具体化应用型型类
{-# LANGUAGE RankNTypes #-}
data ApplicativeInstance f = ApplicativeInstance
{ pure :: forall a. a -> f a
, amap :: forall a b. (a -> b) -> f a -> f b
, ap :: forall a b. f (a -> b) -> f a -> f b
}
listApplicative = ApplicativeInstance
{ pure = \a -> [a]
, amap = map
, ap = \fs xs -> case fs of
[] -> []
f:fs' -> map f xs ++ ap cartesianListApplicative fs' xs
}
zipListApplicative = ApplicativeInstance
{ pure = \a -> [a]
, amap = map
, ap = \fs xs -> case (fs, xs) of
([], _) -> []
(_, []) -> []
(f:fs', x:xs') -> f x : ap zipListApplicative fs' xs'
}
现在,我们获得了我们想要的实例指定的权力。但是,我们失去了隐式选择实例的权力:选择现在必须是明确的。
ghci> ap listApplicative [(+1), (*3)] [1 .. 5]
[2,3,4,5,6,3,6,9,12,15]
ghci> ap zip
zip zipListApplicative zipWith3
zip3 zipWith
ghci> ap zipListApplicative [(+1), (*3)] [1 .. 5]
[2,6]
参见: http://lukepalmer.wordpress.com/2010/01/24/haskell-antipattern-existential-typeclass/