Lenses in Prolog via DCG, maybe or not?

Played with lenses in Prolog. Lenses are a kind of microscope that allows you to scale the structure and do some reading or writing in functional mode. Basically, my starting point is the following simulation of setters and declarative getters in Prolog:

Getter: Just <closure>,
called call(<closure>, X, Y), it will extract the value Yfrom X.

Declarative setter: The same <closure>, but used with a different reality,
is called call(<closure>, X, Y, Z), it will update with a Xnew value Y, giving a new one Z.

I quickly came to the definition of the lens composition operator @, which can be used to combine two lenses into a new one, only based on their closures. An example and definition are given in the appendix. But in accordance with this article, lenses can be made simply composite.

In my opinion, when something is composite, it can be easily modeled using DCG. I can do this for a getter as follows, but I have not yet defined a way to do this for a declarative setter:

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

How would I simulate the setter composition in DCG? Is it possible, perhaps, a change in internal assumptions about how getters and declarative setters are modeled so that the result is simply composite?

Regards

Appendix: Here is an example of some setters and getters:

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

Here is a lens composition simulation:

:- 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)).
+4
1

, , - . , . :

Getter:
- .
:
- .

, . , .

, DCG . DCG, .

/* composition */
@(C1, C2) :-
   call(C2),
   call(C1).

Bye

: :

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

Source: https://habr.com/ru/post/1629227/


All Articles