functional-programming - 通过 DCG 在 Prolog 中使用镜头,可能与否?

标签 functional-programming prolog composition dcg lenses

在 Prolog 中玩弄镜头。镜头是一种显微镜,可以放大结构并以功能方式进行一些读取或写入。基本上我的出发点是以下 Prolog 中 setter 和声明性 getter 的建模:

setter/getter :只是一个 <closure> ,
称为 call(<closure>, X, Y) ,
这将检索值 Y来自 X .

声明式 setter :<closure>但使用不同的数量,
称为 call(<closure>, X, Y, Z) ,这将更新 X按新值 Y给一个新的Z .

我很快就得出了镜头合成运算符 @ 的定义,它可用于将两个镜头组合成一个新镜头,仅基于它们的闭合。附录中提供了一个示例和定义。但是根据这个article镜头可以简单地合成。

在我看来,当某些东西是组合的时,它可以很容易地通过 DCG 建模。我可以按如下方式为 getter 执行此操作,但我还没有找到为声明性 setter 执行此操作的方法:

/* Getter composition as DCG */
@(C1, C2) --> 
     call(C1),
     call(C2).

我将如何在 DCG 中对 setter 组合进行建模?这是可能的,也许会改变 getter 和 declarative 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)).

最佳答案

有一种解决方案具有进一步的间接性,但也有可能以某种方式预编译访问路径。我们再次将访问路径视为闭包,但这次它们修改了延续函数。有两种类型的延续:

setter/getter 续传:
- 在返回之前转换值。
声明式 setter 继续:
- 在更新之前通过附加参数转换值。

访问路径元素现在转换两个延续,以提供新的延续。访问路径元素转换是组合式的,因此首先应用内部访问元素。

附录中给出了一些示例延续,然后我们可以通过 DCG 对访问元素的组合进行建模,如下所示。注意 DCG 正文中的顺序,这反射(reflect)了上述访问元素的顺序。

/* 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)).

关于functional-programming - 通过 DCG 在 Prolog 中使用镜头,可能与否?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35463383/

相关文章:

c# - 重命名高阶列表操作背后的基本原理

c# - 如何使用 Deedle 进行基于行的处理(帧输入和帧输出)

haskell - 将 compose 应用于 fmap

F# 列表中所有其他元素的总和

Scala 函数文字和方法以及下划线

prolog - 如何在 prolog 语句中表示一个句子

prolog - 我已经定义了多个似乎具有共同形式的谓词

prolog - 关于 Prolog 语法

c++ - 可组合的 C++ 函数装饰器

haskell - 为什么 kleisli 组合期望纯值?