灵感来自关于ADT之间的多态函数的一个问题 https://stackoverflow.com/q/25192250/596361我试图在多个(不仅仅是 2 个)类型之间创建同构,这样每次我需要同构但不相同的类型时,我都可以在代码中添加一些convert
.
假设我有 3 个 ADT:
data AB = A | B deriving (Show)
data CD = C | D deriving (Show)
data EF = E | F deriving (Show)
Using lens http://hackage.haskell.org/package/lens我可以在AB和CD、CD和EF之间实现2个同构:
{-# LANGUAGE MultiParamTypeClasses #-}
class Isomorphic a b where
convert :: Iso' a b
instance Isomorphic AB CD where
convert = iso ab2cd cd2ab
where ab2cd A = C
ab2cd B = D
cd2ab C = A
cd2ab D = B
instance Isomorphic AB EF where
convert = iso ab2ef ef2ab
where ab2ef A = E
ab2ef B = F
ef2ab E = A
ef2ab F = B
转换A
to E
简单:A^.convert :: EF
。转换D
to B
也很容易:D^.from convert :: AB
。但如果我想从C
to E
via A
,我必须为每个中间转换注释类型:
(C^.from convert :: AB)^.convert :: EF
我明白为什么编译器无法推断中间类型。可能存在多种同构,通过这些同构我们可以得到C
to E
。但是我可以简化我的代码,这样我就不用到处手动注释类型了吗?
我可以编写另一个实例来直接在之间进行转换CD
and EF
,但是如果我有超过 3 种类型怎么办?如果我有 5 个同构类型,则必须指定 10 个实例,因为同构对象之间的同构数量是完整图中的边数,这是一个三角数 http://oeis.org/A000217。我宁愿指定n-1
实例,权衡是我写更多convert
or from convert
.
是否有一种惯用的方法可以使用以下方法在多种类型之间建立同构Iso http://hackage.haskell.org/package/lens/docs/Control-Lens-Iso.html from lens
这样样板数量最少,而且我不必对所有内容进行类型注释?如果我必须使用 TemplateHaskell 来实现这一点,我该怎么做?
动机是,在我的作品中,我有许多极其复杂但愚蠢的类型,其中() -> (() -> ()) -> X
and ((), X)
同构于X
。我必须手动包装和展开所有内容,并且我想要一些多态方法来将复杂类型减少为更简单的同构类型。