gpt4 book ai didi

haskell - 如何为特定类型实现类似Getter的镜头?

转载 作者:行者123 更新时间:2023-12-02 13:17:48 24 4
gpt4 key购买 nike

给出一般的Getter类型

type Getter s a = forall f. (Contravariant f, Functor f) => (a -> f a) -> s -> f s


我将如何为一对元组实现一个吸气剂?我想上面的类型代表了部分应用的功能,而缺少的部分正是让我感到困惑的地方。

除此之外,我不了解逆约束。可能是为了使镜头类型更像,但功能还不够吗?

最佳答案

在类型Getter s a中,类型s表示以某种方式“包含”类型为a的值的“对象”,getter可以以某种方式“提取”该值。

如果要实现一对吸气剂,则s = (x, y)a可能是xy,这取决于要提取的元素。为了清楚起见,我们要提取第一个元素。然后a = x

好的,因此您的函数应如下所示:

firstElementGetter :: Getter (x, y) x


现在,如果扩展 Getter的定义,则会得到:

firstElementGetter :: (blah-blah) => (x -> f x) -> (x, y) -> f (x, y)
firstElementGetter h (x, y) = ...


这意味着您的函数将获得两个参数:(1)一个可以在函子 h中“包装”一个 x的函数 f,以及(2)一个元组 (x, y);它需要返回包装在函子 (x, y)中的元组 f。让我们看看是否可以做到这一点。

首先,我们有一个函数 h,它带有类型为 x的参数。方便地,我们也有这种类型的 x。让我们应用它: h x。其结果的类型为 f x。我们如何将其转换为 f (x, y)

好吧, Functor的本质是您可以在其上进行映射。那么我们可以在 f x上映射什么功能以获得 f (x, y)?这样的功能显然需要具有 x -> (x, y)类型-瞧!我们拥有构造此功能的所有部分!我们可以采用现有的 y并将其重新组合为元组: \xx -> (xx, y)

现在,我们拥有履行吸气剂合同的一切:

firstElementGetter :: (blah-blah) => (x -> f x) -> (x, y) -> f (x, y)
firstElementGetter h (x, y) = fmap (\xx -> (xx, y)) (h x)




从根本上讲,这就是所有光学器件的工作原理-它们是吸气剂,导线,棱镜还是其他。然后,消费者可以通过选择正确的函子 f和正确的包装函数 h来使他们做不同的事情。

例如,消费者可以通过选择此函子,使用您的吸气剂从元组中“提取”第一个元素:

data Const a b = Const a

instance Functor (Const a) where
fmap f (Const a) = Const a


请注意,它是如何完全忽略类型 b的。实际上并没有“包装”它的值,并且 fmap实现也没有涉及它。您可能会说这是“伪”函子。我们将利用它来发挥我们的优势!

对于功能 h,我们将选择 Const。它适合该类型,因为任何 Const :: x -> Const x foofoo都与 x -> Const x x兼容,而 x -> f xf = Const x匹配所需的类型 h = Const。我知道,这有点令人难以置信,但请多多包涵。

现在,如果 h x,则我们的吸气剂将忠实地调用 Const x,这将返回 fmap,该吸气剂将返回 fmap,但是由于我们的 fmap定义将忽略其第一个参数,因此 仍然是相同的 Const x,然后吸气剂将返回它。现在,我们要做的就是拆开包装,我们完成了!

getFirst :: (x, y) -> x
getFirst pair =
let (Const x) = firstElementGetter Const pair
in x




Contravariant部分是一个聪明的类型级别的黑客。请参见,当函子 f不仅是 Functor,而且是 Contravariant时,它必须具有上述 Const类型的形状-即它不能在内部“包装”其类型参数的值。

可以将 Functor视为“产生”(或“包含”)值的事物,而将 Contravariant视为“消耗”值的事物。如果必须同时使用“包装器”类型,则实现它的唯一方法是仅假装“使用”或“产生”值,而在后台忽略它们。我知道这不是一个很明确的解释,但我无法做得更好。您将看到尝试实现这样的类型。

因此,给 Getter这个怪异的约束,就像确保它唯一可以做的就是“获取”值,而不是“设置”或“转换”该值一样。


getter的最简单实现是 s -> a
(a -> x) -> s -> x是一种不太简单的实现-连续传递样式,但与上一个等效。
一个更简单的实现是 (a -> Const x a) -> s -> Const x s-我只是用不同的 aConst x foo替换了两个 foo,但这仍然与前一个等效。


尽管第一个(最简单的)定义可以实际获取,但最后一个定义的优点是具有与其他镜片兼容的特征,因此可以在镜片组合物中使用这种吸气剂。

关于haskell - 如何为特定类型实现类似Getter的镜头?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57436243/

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