gpt4 book ai didi

haskell - 使用镜头的 3 种或更多类型之间的同构

转载 作者:行者123 更新时间:2023-12-03 15:17:07 25 4
gpt4 key购买 nike

灵感来自 a question on polymorphic function between ADTs我正在尝试在多个(不仅仅是 2 个)类型之间创建同构,这样每次我需要一个同构但不同的类型时,我都可以在我的代码中添加一些 convert .

假设我有 3 个 ADT:

data AB = A | B deriving (Show)
data CD = C | D deriving (Show)
data EF = E | F deriving (Show)

使用 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

转换 AE很简单: A^.convert :: EF .转换 DB也很简单: D^.from convert :: AB .但是如果我想从 C 转换至 E通过 A ,我必须为每个中间转换注释类型:
(C^.from convert :: AB)^.convert :: EF

我理解为什么编译器不能推断中间类型。可能有几个同构可以从 C 得到。至 E .但是我可以简化我的代码,这样我就不用在任何地方手动注释类型了吗?

我可以再写一个实例来直接在 CD 之间进行转换。和 EF ,但是如果我有超过 3 种类型怎么办?如果我有 5 个同构类型,我必须指定 10 个实例,因为同构对象之间的 iso 数量是完整图中的边数,即 triangular number .我宁愿指定 n-1实例,权衡一下,我写了更多 convertfrom convert .

有没有一种惯用的方法来使用 Iso 在多种类型之间建立同构?来自 lens这样样板的数量最少,我不必对所有内容进行类型注释?如果我必须为此使用 TemplateHaskell,我该怎么做?

动机是在我的工作中,我有许多复杂得可笑但愚蠢的类型,其中 () -> (() -> ()) -> X((), X)X 同构.我必须手动包装和展开所有内容,我想要一些多态方法来将复杂类型减少为更简单的同构类型。

最佳答案

您可以将您的同构构造为星图:具有所有其他连接到的规范“集线器”类型。缺点是您必须在每个实例中明确指定集线器,并且您只能在共享集线器的类型之间进行转换。但是,您的两个要求(良好的类型推断和线性数量的实例)将得到满足。以下是你将如何做到这一点:

{-# LANGUAGE TypeFamilies #-}
import Control.Lens
import Unsafe.Coerce

data AB = A | B deriving (Show)
data CD = C | D deriving (Show)
data EF = E | F deriving (Show)

class Isomorphic a where
type Hub a
convert :: Iso' a (Hub a)

viaHub :: (Isomorphic a, Isomorphic b, Hub a ~ Hub b) => a -> b
viaHub x = x ^. convert . from convert

instance Isomorphic AB where
type Hub AB = AB
convert = id

instance Isomorphic CD where
type Hub CD = AB
convert = unsafeCoerce -- because I'm too lazy to do it right

instance Isomorphic EF where
type Hub EF = AB
convert = unsafeCoerce

在 ghci 中:
> viaHub A :: EF
E
> viaHub A :: CD
C
> viaHub E :: AB
A
> viaHub E :: CD
C

以下是您可以如何将其用于您的示例:
class Unit a where unit :: a
instance Unit () where unit = ()
instance Unit b => Unit (a -> b) where unit _ = unit

instance Isomorphic X where
type Hub X = X
convert = id

instance (Unit a, Isomorphic b) => Isomorphic (a -> b) where
type Hub (a -> b) = Hub b
convert = iso ($unit) const . convert

instance Isomorphic a => Isomorphic ((), a) where
type Hub ((), a) = Hub a
convert = iso snd ((,)()) . convert

instance Isomorphic a => Isomorphic (a, ()) where
type Hub (a, ()) = Hub a
convert = iso fst (flip(,)()) . convert

现在你将拥有,例如
viaHub :: (() -> (() -> ()) -> X) -> ((), X)

关于haskell - 使用镜头的 3 种或更多类型之间的同构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39417445/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com