I want to reintroduce Prolog dicts into Dogelog runtime.
But they shoud also give me module access, thus the
dot '.'/2 should replace ':'/2, and they should give me
object access, thus the dot '.'/2 should replace '::'/2
as well. Is this possible? There is now a new idea
inspired by Python and JavaScrip.
The core idea is:
When we access some dict via '.'/2, a built-in will
be executed. This built-in need not only perform an
association lookup, it can also do more.
By only modifying the behaviour of '.'/2 itself, it should
be possible to create a variety of behaviours, even
corresponding to '::'/2, i.e. single dispatch!!!
Lets make two examples. The syntax of a method call
will be like it was for (::)/2 except that the dot '.'/2 is used.
So on the surface we will see:
Receiver.Method(Arg1,..,Argn)
This will be translated into the dict access built-in, which
for illustration purpose is simply '.'/3. And more consequently
than in the past, a call/n invokation:
'.'(Receiver, Method, Temp),
call(Temp, Arg1, .., Argn)
This is new that call/n is involved. In the past we had some
implementation (::)/2 wasnt further factored into the dictionary
getter and the meta call. We can now do the following:
1) For inheritance '.'/2 can follow some reexport chains. But
unlike our old take of modules and reexport, these chains
would now also exist for dicts.
2) For virtual methods '.'/2 can return a closure. So basically
if Method hits a virtual Function in the dictionary
it would return Function(Receiver), a compound and not
simple Function. When this return value is supplied
to the meta call, the net effect will be that Function(Receiver,
Arg1, .., Argn) is called, as desired for a virtual method.
Combining 1) and 2) means that internally '.'/3 needs either
a '.'/4 realization, that the on behalf Receiver can be passed
down in case following a reexport chain hits a virtual Function.
Or the result of '.'/3 calls another '.'''/2 which returns either
(Value,0) or (Value,1) depending on whether non-virtual or
virtual, and the wrapping is done in '.'/3.
Mostowski Collapse schrieb am Mittwoch, 25. August 2021 um 03:27:31 UTC+2:
I want to reintroduce Prolog dicts into Dogelog runtime.
But they shoud also give me module access, thus the
dot '.'/2 should replace ':'/2, and they should give me
object access, thus the dot '.'/2 should replace '::'/2
as well. Is this possible? There is now a new idea
inspired by Python and JavaScrip.
The core idea is:
When we access some dict via '.'/2, a built-in will
be executed. This built-in need not only perform an
association lookup, it can also do more.
By only modifying the behaviour of '.'/2 itself, it should
be possible to create a variety of behaviours, even
corresponding to '::'/2, i.e. single dispatch!!!
Why do it this way, so complicated? Well we want to profit
from the split into lookup '.'/3 and simple meta call call/n. We
could then replicate for example this Python example,
when x is an object and f is a virtual function, then:
x.f()
and this here:
xf = x.f
xf()
Do the same. How is this possible? Python gives a nice explanation:
9.3.4. Method Objects
"If you still don’t understand how methods work, a look at the implementation can perhaps clarify matters. When a non-data
attribute of an instance is referenced, the instance’s class is
searched. If the name denotes a valid class attribute that is a
function object, a method object is created by packing (pointers to)
the instance object and the function object just found together
in an abstract object: this is the method object. When the method
object is called with an argument list, a new argument list is
constructed from the instance object and the argument list,
and the function object is called with this new argument list." https://docs.python.org/3/tutorial/classes.html
Interestingly Java and JavaScript support such method
objects. I was always marveling why the method handles have
a bind() factory method, that binding a parameter and reducing
the number of remaining parameters. But this is exactly what
a future dicts should be able to do. If they step over a virtual function, they should bind it to the given receiver.
Mostowski Collapse schrieb am Mittwoch, 25. August 2021 um 03:38:13 UTC+2:
Lets make two examples. The syntax of a method call
will be like it was for (::)/2 except that the dot '.'/2 is used.
So on the surface we will see:
Receiver.Method(Arg1,..,Argn)
This will be translated into the dict access built-in, which
for illustration purpose is simply '.'/3. And more consequently
than in the past, a call/n invokation:
'.'(Receiver, Method, Temp),
call(Temp, Arg1, .., Argn)
This is new that call/n is involved. In the past we had some implementation (::)/2 wasnt further factored into the dictionary
getter and the meta call. We can now do the following:
1) For inheritance '.'/2 can follow some reexport chains. But
unlike our old take of modules and reexport, these chains
would now also exist for dicts.
2) For virtual methods '.'/2 can return a closure. So basically
if Method hits a virtual Function in the dictionary
it would return Function(Receiver), a compound and not
simple Function. When this return value is supplied
to the meta call, the net effect will be that Function(Receiver,
Arg1, .., Argn) is called, as desired for a virtual method.
Combining 1) and 2) means that internally '.'/3 needs either
a '.'/4 realization, that the on behalf Receiver can be passed
down in case following a reexport chain hits a virtual Function.
Or the result of '.'/3 calls another '.'''/2 which returns either (Value,0) or (Value,1) depending on whether non-virtual or
virtual, and the wrapping is done in '.'/3.
Mostowski Collapse schrieb am Mittwoch, 25. August 2021 um 03:27:31 UTC+2:
I want to reintroduce Prolog dicts into Dogelog runtime.
But they shoud also give me module access, thus the
dot '.'/2 should replace ':'/2, and they should give me
object access, thus the dot '.'/2 should replace '::'/2
as well. Is this possible? There is now a new idea
inspired by Python and JavaScrip.
The core idea is:
When we access some dict via '.'/2, a built-in will
be executed. This built-in need not only perform an
association lookup, it can also do more.
By only modifying the behaviour of '.'/2 itself, it should
be possible to create a variety of behaviours, even
corresponding to '::'/2, i.e. single dispatch!!!
Interesting find, after some discussion Prolog vs LISP:
The native code for Roomba is written in a dialect of Lisp. https://en.wikipedia.org/wiki/Roomba#Hacking_and_extending_Roomba
and the Roomba, the autonomous robotic vacuum cleaner, whose software
is written in L, a downwardly compatible subset of Common Lisp. https://gigamonkeys.com/book/introduction-why-lisp.html
L – A Common Lisp for Embedded Systems https://www.researchgate.net/publication/2949173
L, from the 2004 paper, is somehow brother
in spirit with Dogelog runtime:
- it should produce reasonably efficient code
- compilation speed should be fast
- it should be target independent
- it should be easy to maintain
But L takes a different approach, since it has a CPU
target and not a high level language target. Nevertheless
interesting paper by Rodney A. Brooks.
LoL
Mostowski Collapse schrieb am Sonntag, 29. August 2021 um 16:35:32 UTC+2:
Interesting find, after some discussion Prolog vs LISP:
The native code for Roomba is written in a dialect of Lisp. https://en.wikipedia.org/wiki/Roomba#Hacking_and_extending_Roomba
and the Roomba, the autonomous robotic vacuum cleaner, whose software
is written in L, a downwardly compatible subset of Common Lisp. https://gigamonkeys.com/book/introduction-why-lisp.html
L – A Common Lisp for Embedded Systems https://www.researchgate.net/publication/2949173
Corr.: The paper is from 1995:
Rodney A. Brooks and Charles Rosenberg,
"L - A Common Lisp for Embedded Systems",
Lisp Users and Vendors Conference, sec. 2.4a, August 1995.
Mostowski Collapse schrieb am Sonntag, 29. August 2021 um 16:40:42 UTC+2:
L, from the 2004 paper, is somehow brother
in spirit with Dogelog runtime:
- it should produce reasonably efficient code
- compilation speed should be fast
- it should be target independent
- it should be easy to maintain
But L takes a different approach, since it has a CPU
target and not a high level language target. Nevertheless
interesting paper by Rodney A. Brooks.
LoL
Mostowski Collapse schrieb am Sonntag, 29. August 2021 um 16:35:32 UTC+2:
Interesting find, after some discussion Prolog vs LISP:
The native code for Roomba is written in a dialect of Lisp. https://en.wikipedia.org/wiki/Roomba#Hacking_and_extending_Roomba
and the Roomba, the autonomous robotic vacuum cleaner, whose software
is written in L, a downwardly compatible subset of Common Lisp. https://gigamonkeys.com/book/introduction-why-lisp.html
L – A Common Lisp for Embedded Systems https://www.researchgate.net/publication/2949173
Lets take a time machine, and go back to the beginnings of
Prolog. In my opinion, a must classic to read, when you want
to talk about Prolog:
Prolog - the language and its implementation compared with Lisp.
David H. D. Warren, Luis M. Pereira, Fernando Pereira:
Artificial Intelligence and Programming Languages 1977: 109-115 http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.65.7097&rep=rep1&type=pdf
From its content:
We argue that pattern matching is a better method for
expressing operations on structured data than
conventional selectors and constructors - both for
the user and for the implementor.
[…]
The second factor favouring Prolog is structuresharing.
Ironically, this technique was first devised by Boyer and
Moore [1972] as a means of saving space. However it is
even more important for its contribution to Prolog’s speed.
Etc… Etc…
I discovered that Python has pattern matching when I implemented
the Python version of the Dogelog runtime. Although I use it only
as a substitute for a simple switch statement, which wasn’t available
before in Python. You could model the Python match via a Prolog clause:
p([A,B]) :- (A=1;A=2), (B=3;B=4).
But the head movement that Jan W. has recently introduced in
SWI-Prolog would not work for (;)/2 in the body, so where is the
Prolog indexing for ('|')/2 patterns in the head?
Because pattern matching is useful for business rules, the
audience of Prolog is possibly not the same as for Rust. You
might have more luck addressing the same people
that are also interested in RuleML.
Pattern matching is quite important for commercial software. Its
easier to write business rules sometimes with pattern matching,
although it has a its trap doors.
Pattern matching is found in a variety of languages now:
Erlang
Haskell
JavaScript
Scala
Rust
Python
What else?
Python has it only officially with release 3.10 this year 2021.
The pattern matching found in Python is funny, since it has
a disjunction operator ‘|’. So you can say:
match x:
case [(1 | 2),(3 | 4)]:
Which doesn’t have a Prolog equivalent. So recently
I was thinking about not only introducing (=>)/2 SSU to
Prolog but also (’|’)/2 in the head. Anybody up to this challenge? Mostowski Collapse schrieb am Dienstag, 31. August 2021 um 12:22:27 UTC+2:
Lets take a time machine, and go back to the beginnings of
Prolog. In my opinion, a must classic to read, when you want
to talk about Prolog:
Prolog - the language and its implementation compared with Lisp.
David H. D. Warren, Luis M. Pereira, Fernando Pereira:
Artificial Intelligence and Programming Languages 1977: 109-115 http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.65.7097&rep=rep1&type=pdf
From its content:
We argue that pattern matching is a better method for
expressing operations on structured data than
conventional selectors and constructors - both for
the user and for the implementor.
[…]
The second factor favouring Prolog is structuresharing.
Ironically, this technique was first devised by Boyer and
Moore [1972] as a means of saving space. However it is
even more important for its contribution to Prolog’s speed.
Etc… Etc…
The bind construct is a facinating construct. Taking a
n-ary function f and binding x1,..,xm parameters, giving
a n-m ary function g = f(x1,..,xm).
This closure construction exists also in Prolog, and is
even part of the ISO core standard. We can simply form
g = call(f,x1,..,xm), it will behave like a bound predicate,
a predicate where some arguments have already an
actual value. But the actual values x1,..,xm can also be
logical variables, so giving it a special spin in Prolog. I am
still thinking about introducing compiled lambdas in Dogelog.
I made an intersting discovery today, concerning a new take
on lambda expression, and maybe making them automatically
compiled. So far there are various lambda libraries, they
differ in how they see variables:
- library(abstract): From Jekejeke Prolog, via (\)/2 it sees variables
in the lambda body as global by default, and you can make
variables from the lambda body local via the (^)/2.
- library(lambda): From Ulrich Neumerkel, it sees variables
in the lambda body as local by default, and you can make
variables from the lambda body global via the (+)/2.
This boils down that some variables in the body will be local
and some will be global, and some syntax will tell which is
which. Now how compile this?
From disjunction and if-then-else indexing there is a new,
which gives a reference data type:
- kb_make_defined(L, P): internal only
The built-in succeeds in P with an annonymous predicate for the clauses L.
By the nature of Prolog clauses, all variables that do not appear
in the head but appear in the body, are local. So how can we
introduce a notion of global variables?
Mostowski Collapse schrieb am Freitag, 3. September 2021 um 15:30:32 UTC+2:
The bind construct is a facinating construct. Taking a
n-ary function f and binding x1,..,xm parameters, giving
a n-m ary function g = f(x1,..,xm).
This closure construction exists also in Prolog, and is
even part of the ISO core standard. We can simply form
g = call(f,x1,..,xm), it will behave like a bound predicate,
a predicate where some arguments have already an
actual value. But the actual values x1,..,xm can also be
logical variables, so giving it a special spin in Prolog. I am
still thinking about introducing compiled lambdas in Dogelog.
I want to reintroduce Prolog dicts into Dogelog runtime.
But they shoud also give me module access, thus the
dot '.'/2 should replace ':'/2, and they should give me
object access, thus the dot '.'/2 should replace '::'/2
as well. Is this possible? There is now a new idea
inspired by Python and JavaScrip.
The core idea is:
When we access some dict via '.'/2, a built-in will
be executed. This built-in need not only perform an
association lookup, it can also do more.
By only modifying the behaviour of '.'/2 itself, it should
be possible to create a variety of behaviours, even
corresponding to '::'/2, i.e. single dispatch!!!
Works like a charm:
?- assertz_book(book{isbn:42, title:foo, year:1973}).
?- assertz_book(book{isbn:69, title:bar, year:1984}).
?- listing(book/2).
book(42, book{isbn:42, title:foo, year:1973}).
book(69, book{isbn:69, title:bar, year:1984}).
?- fetch_book(book{isbn:42, title:T}).
T = foo.
?- fetch_book(book{isbn:I, title:bar}).
I = 69.
?- retract_book(book{isbn:42, title:T}).
T = foo.
?- listing(book/2).
book(69, book{isbn:69, title:bar, year:1984}).
Mostowski Collapse schrieb am Donnerstag, 9. September 2021 um 13:55:02 UTC+2:
Isnt this little trick known? One can make clause indexing
without head unification. For example if you want indexing
over some book id. One could do instead of this proposal:
book(book{title: "I Am Malala",
author: 'Malala Yousafzai',
publisher: 'Little, Brown & Co',
year: 2013,
isbn: 9780316322409,
edition: 1}).
Etc..
One would store:
book(9780316322409, book{title: "I Am Malala",
author: 'Malala Yousafzai',
publisher: 'Little, Brown & Co',
year: 2013,
isbn: 9780316322409,
edition: 1}).
Etc..
And then define, to avoid that retract commits too early
I use clause/3 and erase/1 combo:
assertz_book(Book) :-
assertz(book(Book.get(isbn,_), Book)).
fetch_book(Select) :-
book(Select.get(isbn,_), Book),
Select :< Book.
retract_book(Select) :-
clause(book(Select.get(isbn,_), Book), true, Ref),
Select :< Book,
erase(Ref).
I am also using the new, from a few weeks ago, get/2
on dict and the older (:<)/2.
Isnt this little trick known? One can make clause indexing
without head unification. For example if you want indexing
over some book id. One could do instead of this proposal:
book(book{title: "I Am Malala",
author: 'Malala Yousafzai',
publisher: 'Little, Brown & Co',
year: 2013,
isbn: 9780316322409,
edition: 1}).
Etc..
One would store:
book(9780316322409, book{title: "I Am Malala",
author: 'Malala Yousafzai',
publisher: 'Little, Brown & Co',
year: 2013,
isbn: 9780316322409,
edition: 1}).
Etc..
And then define, to avoid that retract commits too early
I use clause/3 and erase/1 combo:
assertz_book(Book) :-
assertz(book(Book.get(isbn,_), Book)).
fetch_book(Select) :-
book(Select.get(isbn,_), Book),
Select :< Book.
retract_book(Select) :-
clause(book(Select.get(isbn,_), Book), true, Ref),
Select :< Book,
erase(Ref).
I am also using the new, from a few weeks ago, get/2
on dict and the older (:<)/2.
Sysop: | Keyop |
---|---|
Location: | Huddersfield, West Yorkshire, UK |
Users: | 292 |
Nodes: | 16 (2 / 14) |
Uptime: | 181:45:49 |
Calls: | 6,616 |
Calls today: | 3 |
Files: | 12,165 |
Messages: | 5,314,390 |