为什么我们需要Control.Lens.Reified?有什么原因不能将Lens直接放入容器中吗?reify到底是什么意思?
发布于 2015-10-13 03:37:21
我们需要具体化的镜头,因为Haskell的类型系统是预测性的。我不知道这到底是什么意思的技术细节,但它禁止像这样的类型
[Lens s t a b]在某些情况下,可以使用
Functor f => [(a -> f b) -> s -> f t]相反,当您深入研究它时,您得到的不是Lens;您得到的是某个函数或另一个函数专用的LensLike。ReifiedBlah的新类型让您可以保持完整的多态性。
在操作上,[ReifiedLens s t a b]是一个函数列表,每个函数都有一个Functor f字典,而forall f . Functor f => [LensLike f s t a b]是一个函数,它有一个Functor f字典并返回一个列表。
至于"reify“是什么意思,字典会说点什么,这在Haskell中似乎会翻译成令人惊叹的各种特定含义。所以对此无可奉告。
发布于 2015-10-13 23:05:11
问题是,在Haskell中,类型抽象和应用程序是完全隐含的;编译器应该在需要的地方插入它们。设计“不可预测”扩展的各种尝试都失败了,编译器会巧妙地猜测将它们放在哪里;因此,最安全的事情最终是依赖于Haskell 98规则:
所以如果我定义一个简单的镜头:1
lensHead f [] = pure []
lensHead f (x:xn) = (:xn) <$> f x并在表达式中使用它:
[lensHead]lensHead会自动应用于一组类型参数;在这一点上,它不再是镜头,因为它在函数器中不再是多态的。结论是:一个表达式总是有一些单态类型;所以它不是一个镜头。(您将注意到,由于类似的原因,lens函数接受类型为Getter和Setter的参数,这两种类型是单态类型。但[Getter s a]并不是镜头列表,因为它们只针对getters。)
reify是什么意思?字典的定义是“make real”。“物化”在哲学中用来指把某物视为真实(而不是理想或抽象)的行为。在编程中,它倾向于将通常不能被视为数据结构的东西表示为一个数据结构。例如,在非常老的Lisp中,过去没有一类函数;相反,您必须使用S表达式来传递“函数”,并在需要调用函数时使用eval。S表达式以您可以在程序中操作的方式表示函数,这称为具体化。
在Haskell中,我们通常不需要像Lisp S表达式这样复杂的具体化策略,部分原因是该语言被设计为避免需要它们;但由于
newtype ReifiedLens s t a b = ReifiedLens (Lens s t a b)有同样的效果,接受一个多态的值,并把它变成一个真正的一等值,它被称为物化。
如果表达式总是具有单态类型,为什么这会起作用?嗯,因为Rank2Types扩展添加了第三条规则:
ReifiedLens是这样一个秩为2的函数;所以当你说
ReifiedLens l您在ReifiedLens的参数周围获得了一个lambda类型,然后l被立即应用于lambda绑定的类型参数。所以l实际上就是eta扩展的。(编译器可以自由减少这一点,只需直接使用l即可)。
然后,当你说
f (ReifiedLens l) = ...在右边,l是一个具有多态类型的变量,因此每次使用l都会立即隐式地分配给表达式进行类型检查所需的任何类型参数。因此,一切都按照您期望的方式运行。
另一种思考方式是,如果你说
newtype ReifiedLens s t a b = ReifiedLens { unReify :: Lens s t a b }两个函数ReifiedLens和unReify的作用类似于显式类型抽象和应用程序操作符;这允许编译器识别出您希望抽象和应用程序发生在哪里,这样就不会出现不可预测类型系统的问题。
1在lens的术语中,这显然不是所谓的“镜头”;我对镜头的全部知识都来自于SPJ对它们的介绍,所以我无法证实这一点。这一点仍然存在,因为多态性仍然是使其同时作为getter和setter工作所必需的。
https://stackoverflow.com/questions/33088563
复制相似问题