首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么我们需要Control.Lens.Reified?

为什么我们需要Control.Lens.Reified?
EN

Stack Overflow用户
提问于 2015-10-13 03:14:26
回答 2查看 335关注 0票数 13

为什么我们需要Control.Lens.Reified?有什么原因不能将Lens直接放入容器中吗?reify到底是什么意思?

EN

回答 2

Stack Overflow用户

发布于 2015-10-13 03:37:21

我们需要具体化的镜头,因为Haskell的类型系统是预测性的。我不知道这到底是什么意思的技术细节,但它禁止像这样的类型

代码语言:javascript
复制
[Lens s t a b]

在某些情况下,可以使用

代码语言:javascript
复制
Functor f => [(a -> f b) -> s -> f t]

相反,当您深入研究它时,您得到的不是Lens;您得到的是某个函数或另一个函数专用的LensLikeReifiedBlah的新类型让您可以保持完整的多态性。

在操作上,[ReifiedLens s t a b]是一个函数列表,每个函数都有一个Functor f字典,而forall f . Functor f => [LensLike f s t a b]是一个函数,它有一个Functor f字典并返回一个列表。

至于"reify“是什么意思,字典会说点什么,这在Haskell中似乎会翻译成令人惊叹的各种特定含义。所以对此无可奉告。

票数 13
EN

Stack Overflow用户

发布于 2015-10-13 23:05:11

问题是,在Haskell中,类型抽象和应用程序是完全隐含的;编译器应该在需要的地方插入它们。设计“不可预测”扩展的各种尝试都失败了,编译器会巧妙地猜测将它们放在哪里;因此,最安全的事情最终是依赖于Haskell 98规则:

  • 类型抽象只发生在函数的顶层,只要在表达式中使用具有多态类型的变量,应用程序就会立即出现。

所以如果我定义一个简单的镜头:1

代码语言:javascript
复制
lensHead f [] = pure []
lensHead f (x:xn) = (:xn) <$> f x

并在表达式中使用它:

代码语言:javascript
复制
[lensHead]

lensHead会自动应用于一组类型参数;在这一点上,它不再是镜头,因为它在函数器中不再是多态的。结论是:一个表达式总是有一些单态类型;所以它不是一个镜头。(您将注意到,由于类似的原因,lens函数接受类型为GetterSetter的参数,这两种类型是单态类型。但[Getter s a]并不是镜头列表,因为它们只针对getters。)

reify是什么意思?字典的定义是“make real”。“物化”在哲学中用来指把某物视为真实(而不是理想或抽象)的行为。在编程中,它倾向于将通常不能被视为数据结构的东西表示为一个数据结构。例如,在非常老的Lisp中,过去没有一类函数;相反,您必须使用S表达式来传递“函数”,并在需要调用函数时使用eval。S表达式以您可以在程序中操作的方式表示函数,这称为具体化。

在Haskell中,我们通常不需要像Lisp S表达式这样复杂的具体化策略,部分原因是该语言被设计为避免需要它们;但由于

代码语言:javascript
复制
newtype ReifiedLens s t a b = ReifiedLens (Lens s t a b)

有同样的效果,接受一个多态的值,并把它变成一个真正的一等值,它被称为物化。

如果表达式总是具有单态类型,为什么这会起作用?嗯,因为Rank2Types扩展添加了第三条规则:

  • 类型抽象发生在某些函数的参数的顶层,具有所谓的秩2类型。

ReifiedLens是这样一个秩为2的函数;所以当你说

代码语言:javascript
复制
ReifiedLens l

您在ReifiedLens的参数周围获得了一个lambda类型,然后l被立即应用于lambda绑定的类型参数。所以l实际上就是eta扩展的。(编译器可以自由减少这一点,只需直接使用l即可)。

然后,当你说

代码语言:javascript
复制
f (ReifiedLens l) = ...

在右边,l是一个具有多态类型的变量,因此每次使用l都会立即隐式地分配给表达式进行类型检查所需的任何类型参数。因此,一切都按照您期望的方式运行。

另一种思考方式是,如果你说

代码语言:javascript
复制
newtype ReifiedLens s t a b = ReifiedLens { unReify :: Lens s t a b }

两个函数ReifiedLensunReify的作用类似于显式类型抽象和应用程序操作符;这允许编译器识别出您希望抽象和应用程序发生在哪里,这样就不会出现不可预测类型系统的问题。

1在lens的术语中,这显然不是所谓的“镜头”;我对镜头的全部知识都来自于SPJ对它们的介绍,所以我无法证实这一点。这一点仍然存在,因为多态性仍然是使其同时作为getter和setter工作所必需的。

票数 8
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/33088563

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档