我正在用Ruby做一个镜头组合器,我不知道它的通用名称是什么未知函数由两个具有相同源类型且其目标类型(使用Benjamin C. Pierce’s terminology)为哈希映射的镜头组成未知函数接受这两个镜头并返回一个与原始镜头具有相同源类型和目标类型的新镜头。
它看起来像这样(ruby语法):
lens_a.get(source)
> {:title => "some title"}
lens_b.get(source)
> {:description => "some description"}
new_lens = unknown_function(lens_a, lens_b)
new_lens.get(source)
> {:title => "some title", :description => "some description"}
在this presentation的第18张幻灯片上可以看到我试图构建的组合器的图表(该幻灯片的标题是“Merge”?”).
我看过haskell的lens docs(我能理解其中的一小部分),但我不知道这是哪个组合子。
上面未知函数的标准名称是什么?如果这个镜头没有一个标准的名字,是否有一些标准的功能可以组成它?如果不是,我可能会叫它合并。
最佳答案
我相信在哈斯克尔,你的组合者的正确想法是
merge :: Lens' s t -> Lens' s t -> Lens' s (t, t)
可能概括为
merge :: Lens' s t -> Lens' s t' -> Lens' s (t, t')
所以你的两个目标类型可能不同我们可以如下“实现”,但这样做会暴露出一个问题
merge l1 l2 = lens pull push where
pull s = (view l1 s, view l2 s)
push s (t1, t2) = set l2 t2 (set l1 t1 s)
特别是,在这个方程的
Setter
边上,我们显式地对我们返回值的方式进行排序。这意味着我们可以使用merge
来轻松构建违反镜头法则的镜头。尤其是,他们违反了普法这里有一个反例newtype Only a = Only a
-- A lens focused on the only slot in Only
only :: Lens' (Only a) a
only inj (Only a) = Only <$> inj a
-- We merge this lens with *itself*
testLens :: Lens' (Only a) (a, a)
testLens = merge only only
-- and now it violates the lens laws
> view testLens (Only 1 & testLens .~ (1,2))
(2,2)
或者,用通俗易懂的英语来说,如果我们用镜头本身,那么
merge
边就变成同一位置上的两个序列集。这意味着,如果我们试图用一对不同的值来设置它,那么只有第二组值会持续存在,因此我们违反了put-get定律。库倾向于避开无效镜头,因此这个组合器不可用。最接近的是
Setter
它有以下类型(受限的)alongside :: Lens' s a
-> Lens' s' a'
-> Lens' (s,s') (a,a')
但是,如您所见,这确保了我们的源也是一种产品类型,因此
lens
s只应用于源的每一侧。如果我们试图编写一个alongside
Setter
来构建dup
的,我们将遇到与以前相同的问题dup :: Lens' a (a, a) -- there are two possible implementations, neither are lenses
dup1 inj a = fst <$> inj a
dup2 inj a = snd <$> inj a
现在,从Ruby的角度来看,所有这些可能都是相当技术性的,毫无意义在Ruby中,您不会有编译器强制的类型安全性,因此您可能会将许多规则混合在一起,从而实现更少的严格性在这种情况下,用其顺序写入语义实现
Lens
可能是有意义的。事实上,根据你给出的例子,我指出的反例在Ruby中甚至不可能出现,因为你的目标类型是一个散列,并且已经确保了唯一的键。
但需要注意的是,如果你仔细观察的话,
alongside
可能会被用来制造不合适的镜头从根本上说,这意味着在更复杂的场景中,使用merge
很容易导致奇怪的错误,这是因为它违反了我们对镜头是什么的直觉对于ruby来说,这可能不是一个大问题,因为复杂的抽象在ruby社区中是不受欢迎的,但这就是为什么我们有这样的规则。关于ruby - 这是什么样的镜头组合器?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/22865170/