C Plus Prolog
github.com
github.com
:- op(400, yfx, :).
?- JSON = {
a: 1, b: "a string",
c: { d: "a compound" }
},
JSON = { a: X, b: Y, c: { d: Z }}
Basically, you don't ;) all we did here is declaring ':' as an infix operator. The next lines bind/unify a term to the var JSON, and the last line is again unification in action (basically destructuring on steroids), binding the vars X, Y, and Z to the respective value 1, "a string", and "a compound" from the previously bound JSON var.You can paste this snippet into [1] and execute it right in your browser to check that indeed X, Y, and Z are bound as described if you wish.
Not that it matters that much. Prolog is really for indeterministically searching a large/infinite space such as in planning (and yes it can be used for theorem proving and program verification as well). It's always fun to see newcomers trying to implement pointless low-level stuff such as list primitives when coming from a functional programming background or even getters/setters.
[1]: https://quantumprolog.sgml.net/browser-demo/browser-demo.htm...
One side note here. Yes you can do indeterministic search but it’s not a property in Prolog. In fact, Prolog execution is completely deterministic without use of randomization.
But I guess that in some domains (e.g. optimization) people would rather shuffle numbers than do a boring 1…1000000000 loops.
If your code is logically correct, it doesn't matter in the end - except if you use the cut-operator which essentially says 'don't look any further, just go with the first match', which will behave (in)deterministically based on the implementation.
I'd say theorem proving is what Prolog "is really for", in the sense that it's a language whose interpreter is an automated theorem prover.
It just so happens that a (first-order) theorem prover is the best tool to explore an infinite space, if it's worth its salt, because that's what it has to do in order to find a proof in the first place.
And of course you can cast all sorts of combinatorial problems like planning and verification as proofs (this sequence of actions reaches this goal state from this starting state).
Edit: incidentally, it's so dumb that the standard for pattern matching in the industry is regexes, with their insufferable, cryptic pandemonium of notations, rather than Prolog, which has got to be the language with the simplest possible syntax in all of computer science this side of Brainfuck. When I was doing my NLP homerwork during my MSc I kept writing small ad-hoc parsers that were all balls of mud around a bunch of regex scripts, and I longed for the simplicity of Prolog and its DCGs (I couldn't use Prolog because the homework was in Python and at the time there was no Janus). Why do programmers do that to themselves?
https://github.com/xonixx/prolog-experiments/blob/main/Prolo...
This was super funny, but obviously absolutely useless
(Something something monads are sequentialness)
I wish there was a way to search for my comments, it sucks that I would have to paginate. I left a lot of comments.
% Each shift needs a nurse).
1 { shift_nurse(Shift, Nurse): nurse(Nurse) } 1 :- shift(shift).
% It cannot be that a nurse does two shifts in a row.
:- nurse(Nurse), shift_nurse(Shift1,Nurse),shift_nurse(Shift2,Nurse), Shift1 + 1 = Shift2.
[0] https://potassco.org/doc/start/Found the original comment: https://news.ycombinator.com/item?id=41756679
Would this still work with ASP?
In practice you would have to write documentation that basically turns into a course on constraint solving in Prolog. There are footguns and somewhat advanced techniques involving control over the execution strategy that are going to trip up newcomers. You'll also have to figure out how to interface with a Prolog implementation.
A compromise might be to use bindings for Z3 or something like the Timefold solver, https://timefold.ai/open-source-solver. Either way it's a good idea to spend some time playing around with Scryer, https://www.scryer.pl/, and Markus Triska's crash course, https://www.metalevel.at/prolog. SWI-Prolog has more conveniences that might make it more suitable for practical applications, but being used to them might make it harder to adapt to e.g. Scryer, Tau or some other implementation.
There's also the Mercury language, it's weirder but also very interesting, https://mercurylang.org/.
Edit: Some people swear by Picat but I have very little experience with it, http://picat-lang.org/.
[1]: https://www.metalevel.at/prolog/timetabling/
[2]: https://github.com/mthom/scryer-prolog/discussions/2519
At a superficial level, it looks a bit like Z3, which I do have some experience with, but I suspect that there's a lot of intricacies to Prolog that don't apply to Z3.
Sadly non-'pure' logical programming is required to get real-world performance (eg. cuts that prune the search tree) which kind of feel like, or is, a leaky abstraction that breaks the magic.
I have had good success in solving logical problems by asking o1 to produce prolog programs.
I learnt Prolog a long time ago and would like to start from scratch.
They aren’t required but are convenient. Excuse brutalizing syntax and formatting but in Prolog you can do:
A(X) :- between(1,3,X).
B(X) :- between(1,1000,X).
?- A(X), B(X).
?- B(X), A(X).
And get either 9 visits or 3000. It’s possible to design a program without cuts but (in my opinion) it’s very hard and doesn’t bring any benefits outside of street cred.Also cuts and pruning long time ago felt like bloated terms (when I didn’t get Prolog) whereas it’s a simple break equivalent in imperative languages loops.
SWI Prolog has great libraries, BTW.
https://web.archive.org/web/20040603192757/research.microsof...
You only get in trouble with the cut when you're just starting out and don't know what you're doing, and write your code in a way that it keeps entering infinite recursion or backtracking until the cows come home. At that point, because you don't yet know how to control those behaviours, you start sowing your code with cuts all over the place, which maybe stops the backtracking and infinite recursion (but maybe not) but it makes it an incomprehensible mess that still doesn't do what you want it to do.
As you grow and learn, you figure out how to control backtracking and recursion by ordering your program clauses and your clause literals in a sensible manner. At that point the use of the cut becomes so regular and formulaic that it might as well be added in by a pre-procesor.
For instance, you want a program that walks over a list and modifies an element if a condition holds, otherwise it continues, until the list is empty. You write:
% Program "skeleton" not meant to be executed but to expose a pattern
modify_list([],Xs,Xs):-
! % We're done, stop trying
modify_list([X|Xs],[Y|Acc],Bind):-
modify_element(X,Y)
,! Don't re-process X!
,modify_list(Xs,Acc,Bind).
modify_list([_X|Xs],Acc,Bind):-
modify_list(Xs,Acc,Bind).
In the example above, the two cuts have a very clear reason to be where they are (they stop unnecessary backtracking) which is immediately obvious by eyballing the program with sufficient experience. The vast majority of the use of cuts in the code you write once you have a bit of experience and understanding of how Prolog works is like that.I have relied heavily on both Z3 and Alloy for ad-hoc jobs, and Prolog doesn't even come close to the inference power, and that's along-side Macsyma and Sage.
I've just made something similar but with JS: C modules in JS.
import * as CModule from "./module.c";
C module gets compiled to native code on load. I think that clear separation of execution models is a good thing.Missed the chance to call it CPP.
I've been thinking over the years how to make prolog more useful. The primary constraint I have is not syntax or expertise, it's how to embed a useful prolog in a 'modern saas microservice' if you will. From what I can gather, this is not being done in the open; perhaps some closed products do it. It's telling that it's much easier to embed Z3 than prolog...
Incidentally this is something I've looked at long time ago and things pointed at SWI Prolog https://www.swi-prolog.org/pldoc/man?section=embedded
The target language for my case was embedding within PHP, that would have meant enough expertise to embed the interpreter, hook it into the PHP runtime, and expose it in the language through some interface. Way over my skill level. Should be certainly doable with any language that can interface at the C language level.
And some example uses: https://github.com/kwon-young/array/blob/master/kernel.pl#L5...
It is also the smoothest way of "declaring an imperative" I've ever seen.
It is also the most amazing use of the parser which is built-in to prolog (no, not the DCG's, the other parser, the railroad/operator precedence parser).
I wish it had been discovered around 1981. The world might be very different.
Not really, plety of software has been written decades before it came to be, and plenty more has not been written in it, after it came to be.
Plus better reach out to something like SICStus if Prolog and performance is something one cares about in the same sentence.