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

Oma*_*man 11 haskell lenses

为什么我们需要Control.Lens.Reified?有什么理由我不能Lens直接放入容器吗?reify无论如何,意味着什么?

dfe*_*uer 12

我们需要具体化的镜头,因为Haskell的类型系统具有预测性.我不知道究竟是什么意思的技术细节,但它禁止类似的类型

[Lens s t a b]
Run Code Online (Sandbox Code Playgroud)

出于某些目的,使用它是可以接受的

Functor f => [(a -> f b) -> s -> f t]
Run Code Online (Sandbox Code Playgroud)

相反,但是当你达到那个目的时,你就得不到了Lens; 你得到一个LensLike专门的一些仿函数或另一个.该ReifiedBlahnewtypes让你挂在充分多态性.

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

至于什么"reify"意味着,好的,字典会说些什么,而这似乎在Haskell中转化为一种相当令人惊叹的特定含义.所以没有评论.


Jon*_*ast 7

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

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

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

lensHead f [] = pure []
lensHead f (x:xn) = (:xn) <$> f x
Run Code Online (Sandbox Code Playgroud)

并在表达式中使用它:

[lensHead]
Run Code Online (Sandbox Code Playgroud)

lensHead自动地应用到一些组类型参数; 在这一点上,它不再是一个镜头,因为它在仿函数中不再是多态的.外卖是:表达总是有一些单形类型; 所以它不是镜头.(你会注意到这些lens函数采用了类型的参数,Getter并且Setter它们是单态类型,出于类似的原因.但是a [Getter s a]不是透镜列表,因为它们专门用于吸气剂.)

什么reify意思?字典定义是'make real'.哲学中使用"具体化"来指代将事物视为真实(而不是理想或抽象)的行为.在编程中,它倾向于将某些通常不能被视为数据结构并将其表示为一个的东西.例如,在非常古老的Lisps中,没有使用成为一流的函数; 相反,你必须使用S-Expressions传递'函数',eval当你需要调用函数时它们.S-Expressions以您可以在程序中操作的方式表示函数,这被称为具体化.

在Haskell中,我们通常不需要像Lisp S-Expressions这样精细的具体化策略,部分原因是该语言旨在避免需要它们; 但是由于

newtype ReifiedLens s t a b = ReifiedLens (Lens s t a b)
Run Code Online (Sandbox Code Playgroud)

具有相同的效果,即获取多态值并将其转换为真正的第一类值,它被称为具体化.

如果表达式总是具有单形类型,为什么这样做?好吧,因为Rank2Types扩展添加了第三条规则:

  • 类型抽象出现在某些函数的参数的顶层,即所谓的rank 2类型.

ReifiedLens是这样的秩-2功能; 所以当你说

ReifiedLens l
Run Code Online (Sandbox Code Playgroud)

你得到一个围绕参数的类型lambda ReifiedLens,然后l立即应用于lambda绑定类型参数.所以l实际上只是eta扩展.(编译器可以自由地减少这个并直接使用l).

然后,当你说

f (ReifiedLens l) = ...
Run Code Online (Sandbox Code Playgroud)

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

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

newtype ReifiedLens s t a b = ReifiedLens { unReify :: Lens s t a b }
Run Code Online (Sandbox Code Playgroud)

两个函数ReifiedLensunReify像显式的类型的抽象和应用运营商行为; 这允许编译器确定您希望抽象和应用程序发生的位置,以至于不会出现具有impredicative类型系统的问题.

[1]在lens术语中,这显然被称为"镜头"以外的东西; 我对镜片的全部了解都来自SPJ对它们的介绍,所以我无法对其进行验证.重点仍然存在,因为多态性仍然是必要的,以使其作为getter和setter工作.