我正在阅读有关镜头的教程,在介绍中,作者lens
通过展示我们如何使用标准 Haskell 实现 OOP 风格的“setter”/“getter”的一些示例来激发这个概念。我对以下示例感到困惑。
假设我们User
按照图 1(下图)定义了一个代数数据类型。本教程(正确地)指出,我们可以通过NaiveLens
数据类型和nameLens
函数实现“setter”功能(也在图 1 中)。图 2 给出了一个示例用法。
我很困惑为什么我们需要如此复杂的构造(即NaiveLens
数据类型和nameLens
函数)来实现“setter”功能,而以下(有些明显的)函数似乎同样能很好地完成这项工作:set' a s = s {name = a}
.
但是,鉴于我的“明显”函数就是 lambda 函数的一部分nameLens
,我怀疑使用下面的构造确实有优势,但是我太密集了,看不出那个优势是什么。我希望其中一位 Haskell 向导可以帮助我理解。
图 1(定义):
data User = User { name :: String
, age :: Int
} deriving Show
data NaiveLens s a = NaiveLens { view :: s -> a
, set :: a -> s -> s
}
nameLens :: NaiveLens User String
nameLens = NaiveLens name (\a s -> s {name = a})
图 2(示例用法):
λ: let john = User {name="John",age=30}
john :: User
λ: set nameLens "Bob" john
User {name = "Bob", age = 30}
it :: User