通过 DCG 在 Prolog 中的镜头,可能与否?
Posted
技术标签:
【中文标题】通过 DCG 在 Prolog 中的镜头,可能与否?【英文标题】:Lenses in Prolog via DCG, possible or not? 【发布时间】:2016-05-29 13:14:21 【问题描述】:在 Prolog 中玩镜头。镜头是一种显微镜,可以放大结构并以功能方式进行一些读取或写入。基本上我的出发点是 Prolog 中的 setter 和声明式 getter 的以下建模:
Getter:只是一个<closure>
,
称为call(<closure>, X, Y)
,
这将从X
检索值Y
。
声明性 Setter: 相同的 <closure>
,但使用不同的 arity,
称为call(<closure>, X, Y, Z)
,这将通过新值Y
更新X
,从而提供新的Z
。
我很快就定义了一个镜头合成运算符@,它可以用来将两个镜头组合成一个新镜头,只是基于它们的闭包。附录中提供了示例和定义。但是根据这个article,镜头可以制作成简单的构图。
在我看来,当某事物具有组合性时,它可以通过 DCG 轻松建模。我可以为 getter 执行此操作,如下所示,但我还没有找到一种方法来为声明式 setter 执行此操作:
/* Getter composition as DCG */
@(C1, C2) -->
call(C1),
call(C2).
如何在 DCG 中为二传手组合建模?这是否可能,也许会改变对 getter 和声明性 setter 的建模方式的初始假设,从而使结果只是组合式的?
最好的问候
附录: 下面是一些 setter 和 getter 的示例:
/* getter */
back(bicycle(X, _), X).
front(bicycle(_, Y), Y).
circumference(wheel(X, _), X).
spokes(wheel(_, Y), Y).
/* setter */
back(bicycle(_, Y), X, bicycle(X, Y)).
front(bicycle(X, _), Y, bicycle(X, Y)).
circumference(wheel(_, Y), X, wheel(X, Y)).
spokes(wheel(X, _), Y, wheel(X, Y)).
这是镜头构图的建模:
:- op(600, xfy, @).
/* getter composition */
@(C1, C2, X, Y) :-
call(C1, X, H),
call(C2, H, Y).
/* setter composition */
@(C1, C2, X, Y, Z) :-
call(C1, X, H),
call(C2, H, Y, J),
call(C1, X, J, Z).
以下是一些运行示例:
Welcome to SWI-Prolog (Multi-threaded, 64 bits, Version 7.3.16)
Copyright (c) 1990-2015 University of Amsterdam, VU Amsterdam
?- call(front@spokes, bicycle(wheel(1330, 12), wheel(1440, 16)), X).
X = 16.
6 ?- call(back@circumference, bicycle(wheel(1330, 12), wheel(1440, 16)), X).
X = 1330.
7 ?- call(front@circumference, bicycle(wheel(1330, 12), wheel(1440, 16)), 1420, X).
X = bicycle(wheel(1330, 12), wheel(1420, 16)).
【问题讨论】:
哇,是啊,标签镜头很多! 【参考方案1】:有一个解决方案具有进一步的间接性,但它也有可能以某种方式预编译访问路径。我们再次将访问路径视为闭包,但这次它们修改了延续函数。延续有两种类型:
Getter 继续: - 在返回值之前对其进行转换。声明性 Setter 继续: - 在更新之前通过附加参数转换值。
访问路径元素现在转换两个延续,以提供新的延续。访问路径元素转换是组合的,首先应用内部访问元素。
附录中给出了一些示例延续,然后我们可以通过 DCG 对访问元素的组合进行建模,如下所示。请注意 DCG 正文中的顺序,这反映了上述访问元素的顺序。
/* composition */
@(C1, C2) :-
call(C2),
call(C1).
再见
附录: 以下是一些转换器定义:
/* transformer construction */
back(F, back(F)).
front(F, front(F)).
circumference(F, circumference(F)).
spokes(F, spokes(F)).
/* getter transformer */
back(F, bicycle(X, _), Y) :- call(F,X,Y).
front(F, bicycle(_, X), Y) :- call(F,X,Y).
circumference(F, wheel(X, _), Y) :- call(F,X,Y).
spokes(F, wheel(_, X), Y) :- call(F,X,Y).
/* setter transformer */
back(F, bicycle(X, Y), Z, bicycle(T, Y)) :- call(F,X,Z,T).
front(F, bicycle(X, Y), Z, bicycle(X, T)) :- call(F,Y,Z,T).
circumference(F, wheel(X, Y), Z, wheel(T, Y)) :- call(F,X,Z,T).
spokes(F, wheel(X, Y), Z, wheel(X, T)) :- call(F,Y,Z,T).
这是镜头组成和一些光阑转换器:
:- op(600, xfy, @).
/* composition */
@(C1, C2, F, G) :-
call(C2, F, H),
call(C1, H, G).
/* stop getter */
id(X,X).
/* stop setter */
id(_,X,X).
以下是一些运行示例:
Welcome to SWI-Prolog (Multi-threaded, 64 bits, Version 7.3.14-1-ga20f192)
Copyright (c) 1990-2015 University of Amsterdam, VU Amsterdam
?- ['lens.pro'].
?- call(front@spokes, id, F), call(F, bicycle(wheel(1330, 12), wheel(1440, 16)), X).
F = front(spokes(id)),
X = 16.
?- call(back@circumference, id, F), call(F, bicycle(wheel(1330, 12), wheel(1440, 16)), X).
F = back(circumference(id)),
X = 1330.
?- call(front@circumference, id, F), call(F, bicycle(wheel(1330, 12), wheel(1440, 16)), 1420, X).
F = front(circumference(id)),
X = bicycle(wheel(1330, 12), wheel(1420, 16)).
【讨论】:
以上是关于通过 DCG 在 Prolog 中的镜头,可能与否?的主要内容,如果未能解决你的问题,请参考以下文章