Rendered at 23:23:16 GMT+0000 (Coordinated Universal Time) with Cloudflare Workers.
schmuhblaster 21 hours ago [-]
As someone who has developed a somewhat weird obsession with Prolog, I can highly recommend Markus Triska's other articles on Prolog. His article on meta-interpreters [0] was particularly inspiring for me.
What do people use Prolog for in the real world? I learned about it on a university course and it seems so esoteric compared to other things on the course. Like something invented just for computer scientists to enjoy.
crustycoder 14 hours ago [-]
I've just rolled out an internal SWI Prolog app that is similar to one linked to elsewhere in the thread [1]. We have a large Cloud estate with 10s of thousands of resources in it. Detecting unused or misconfigured resources manually isn't practical, and there are significant cost savings to be had by cleaning things up. The Prolog app reads in JSON resource snapshots, creates an in-memory database of facts from it and then applies rules to detect issues. Most of the rules are simple and the ones for detecting unused resources (3 LOC) or resources that reference other non-existent resources (7 LOC) are entirely generic. There's also link metadata that models the possibility of links existing between resource types, even if they aren't always there in practice.
There's TUI that allows querying of issues and the resource hierarchy. Issues can also be output as JSON which is fed into a LLM to produce cleanup actions and management reporting.
The Prolog app is very fast, considering what it's doing, largely because it makes heavy use of tabling so once an issue has been detected it's not recomputed when queries are made.
This sounds like a very useful way to use Prolog. I would also guess that is a more efficient and direct method for performing pattern detection vs an LLM.
crustycoder 2 hours ago [-]
Yes, exactly. The issue detection step isn't particularly well-suited to a LLM, as it will tell you itself. The issues can be established deterministically by examining the Cloud resource data with a set of relatively simple rules, and Prolog is ideal for that. Where a LLM comes into the picture is analysis of the symptoms - resource relationships, ages, ownership, hypothesising root causes, generating cleanup plans, management reporting and so on. The interface between Prolog and the LLM is a JSON file containing the detected symptoms which is described to the LLM by a Skill. It all works pretty well.
YeGoblynQueenne 5 hours ago [-]
What's your TUI made with? I'm kind of imagining some kind of n-curses based thing here tbh, using SWI-Prolog's C interface? Nothing like that?
crustycoder 3 hours ago [-]
It's not that sophisticated ;-) There's command editing using readline, result pagination using less and I output links to the reports and the Cloud console using ANSI HTTP link escapes. Primitive but sufficient.
xlii 16 hours ago [-]
My last use case: Testing Scenario Generator.
I have a application that has actions and actions can happen pretty much in any order. By default all scenarios should be an error except for ones that are in the boundary of logical steps, e.g.
A few years ago I wrote a workforce scheduling program designed to be used by non-programmers. I worked in a restricted environment so couldn't install anything. The whole thing ran on SWIPL's web offering.
Users simply had to change the basic "facts" (who was available on what days, how many people were needed), and the program solved for the various constraints and offered solutions.
It was maybe about 300 lines of Prolog, no complex dependencies. It replaced a pile of Python scripts that required a lot of state, didn't really work, and could only run on a few specific computers.
For regular users, it was relatively easy to understand and change the facts. SWIPL for web also offers a nice "notebook" interface that lets you mix data, code, and markdown / output blocks so the documentation was inline.
tannhaeuser 11 hours ago [-]
"Planning, optimization, diagnostics, and complex configuration" [1]
Prolog also works extremely well as a target language for code generation by LLMs for these domains due to it being "higher up in the food chain" compared to procedural languages so to speak, and because Prolog was originally envisioned for classic NLP and hence has a corpus of one-to-one mappings from natural language to logic (as in the example in [3]). So well in fact that even with last-gen models textual descriptions for suitable problems become the bottleneck and you can in many cases just go straight to Prolog code instead ([2]).
20+ years ago, it was the backend for the business rules engine that processed various logging and monitoring events. The concept was interesting, the performance was terrible, and businesses mostly didn't want to touch it. After I setup clients with a generic set of rules that worked on Prolog facts, most all of my clients were happy to limit their changes to only those fact files.
_flux 16 hours ago [-]
Many years ago Maemo (the mobile OS from Nokia) had the profile manager (day mode/night mode etc) written in Prolog. To me it seems like it's a very appropriate application for it.
mstuyt 3 hours ago [-]
Many years ago I used Prolog (BIM Prolog, I believe ) since it was used as an event correlation engine in Tivoli Enterprise Console (IBM). Fun to assert predicates for complex correlation logic.
DanielHB 15 hours ago [-]
The JS package manager Yarn had an experimental feature to define dependency constraints using prolog, it made for very concise way to represent the logic.
It never got released for good though. I actually had need of such feature for a project but I thought that using an exoteric programming language and an experimental feature was a bit much. I ended up setting up those constraints as a CI check hand-made script and the code was surprisingly large (~300 lines), but not that hard to understand.
I used it working on automated tests for telecoms protocols, the practical problem reduces to solving instances of the Pressburger arithmetic, triple exponential time in general (ouch) but we got some results anyway using heuristics. Prolog's a nice space to do high-level heuristics.
christophilus 1 days ago [-]
Dunno about Prolog, but Datomic uses datalog for its query language, and it’s excellent. Datalog is a subset of Prolog.
gobdovan 22 hours ago [-]
Datalog is not a subset of Prolog. It looks that way because both are based on Horn clause logic, while Prolog is more expressive.
This loops Prolog, but terminates in Datalog:
p :- p.
p.
?- p.
This is because the underlying mechanism is completely different. Datalog is like SQL with recursion, you start with known facts and repeatedly applies rules to derive all consequences until nothing new appears. In Prolog, you start from the query and works backward through rules until it either finds a proof or fails.
So, Datalog treats Horn clauses as database constraints/inference rules while Prolog treats Horn clauses as a search program. They use the same mathematical substrate, but completely different computational models.
ux266478 9 hours ago [-]
The full story the other comments don't cover:
- Datalog is a syntactic subset of Prolog
- Real Prolog implementations generally have the ability to configure their runtimes such that it becomes a proper superset of Datalog
ted_dunning 1 days ago [-]
Datalog may appear to be a subset, but it is quite distinct semantically.
raffael_de 1 days ago [-]
What is Datalog used for nowadays?
gobdovan 22 hours ago [-]
General programming [0], static analysis [1], RDF triple stores [2], authorization systems [3], incremental computation [4] [5], graph DBs [6]. But it is kind of hard to define Datalog exactly, since it is an entire family of technologies based on logic, each extending a clean mathematical model differently.
thanks for your list. appreciated. my question should have been more precise. last time I checked all the Datalog projects I found where either old, unmaintained or have only a single contributor. and that is also true for your examples. I really like Prolog and would love to use Datalog for (RDF) knowledge graph inference.
harperlee 6 hours ago [-]
Then use them! Then those projects will cease having a single contributor or being unmaintained. This doesn't need to be a binary decision (either there is no risk or I won't use it), just choose the project / scope with knowledge that there is some risk in a small community; so internal use rather than client facing, specialized uses, etc.
raffael_de 5 hours ago [-]
not sure how using a project adds a contributor. but for the latter - I'm not sufficiently competent at Prolog and friends to meaningfully contribute. I do donate money, though, to projects I regularly use - like for example FreeTube or Linux Mint.
AlotOfReading 24 hours ago [-]
Other than databases, program analysis. The polonius borrow checker in rustc uses datalog internally.
But you can use it for lots of things. Whenever I'm frustrated with graph based tools being slow (like build systems), I run the graph through a datalog engine for comparison. It's usually much, much faster.
fleur-de-lotus 17 hours ago [-]
Not used.
Quote about prolog:
The elegant solution is not efficient.
The efficient solution is not elegant.
Antibabelic 16 hours ago [-]
Prolog is an elegant abstraction. One of the points of abstractions is that they let us concentrate our optimization efforts in one place. Prolog benefits from many decades of research into how to make it work fast. When your problem does require a Prolog-shaped solution the most sensible thing to do is to use a highly optimized Prolog system instead of reinventing a naive algorithm yourself. Your "inelegant" solution will not be faster.
(This is also the problem with "I'll just quickly implement a Prolog-like DSL when I need it". Sometimes not a bad idea, but you have to be realistic. Your "lightweight" Prolog will be worse in every way compared to serious Prolog implementations).
taneq 16 hours ago [-]
I feel like an inefficient solution is inelegant by definition.
Smaug123 15 hours ago [-]
Nah - for example, AIXI is so inefficient that it's literally uncomputable, but it is beautiful.
Antibabelic 16 hours ago [-]
Richard O'Keefe in The Craft of Prolog: "Elegance is not optional".
zingar 15 hours ago [-]
That sounds intuitively right but breaks down when you ask “inefficient at what?”. Are you efficient with CPU cycles or efficient with human working memory?
AdieuToLogic 22 hours ago [-]
> What do people use Prolog for in the real world?
Here[0] is an example of using Ruby and Prolog to solve a real-world AWS management problem.
That is brilliant and simple and shows that when Graph Databases were a big thing they probably should have used Prolog as a front end.
darkwi11ow 11 hours ago [-]
https://www.openpolicyagent.org/docs/policy-language
Not quite Prolog as they teach in universities, but its close descendant. Used for policy evaluation, e.g. to validate tree-structured datasets against arbitrary permission rule sets.
segmondy 23 hours ago [-]
Everything, you heard the joke about those who don't know Lisp end up reinventing it, well, the same can be said for Prolog.
mamp 19 hours ago [-]
One doesn’t simply create a Warren Abstract Machine by accident
nagaiaida 18 hours ago [-]
no, first one goes down some wrong avenues before backtracking
Zenlisp it's similar but almost gives an intro CS course (pre SICP)
for the cheap implementing discrete Math and tons of stuff
in pure Lisp, even rational and complex numbers. The end
chapter it's about logic programmer of course.
Like most "Prolog implemented in a LISP" examples, that's not Prolog. It's a Prolog-like LISP language that is missing the point. Implementing Prolog in Lisp is only "trivial" if you try to do something trivial and call it "implementing Prolog in LISLP", instead of actually, you know, implementing Prolog. In Lisp.
Since we're discussing an article by Markus Triska, and he's commented on the same thing, I'll let him do the honours:
Some online books show how to implement simple "Prolog" engines in Lisp. These engines typically assume a representation of Prolog programs that is convenient from a Lisp perspective, and can't even parse a single proper Prolog term. Instead, they require you to manually translate Prolog programs to Lisp forms that are no longer valid Prolog syntax. With this approach, implementing a simple "Lisp" in Prolog is even easier ("Lisp in Prolog in zero lines"): Manually translate each Lisp function to a Prolog predicate with one additional argument to hold the original function's return value. Done. This is possible since a function is a special case of a relation, and functional programming is a restricted form of logic programming.
I'll just add that this idea of a "trivial" implementation of Prolog in Lisp seems to come from SICP which itself proudly shows off how to "trivially" do the job. I once sat through a couple of hours of lecturing on Logic Programming and Prolog by Gerald Sussman, on youtube, just to try and form a mental model of his mental model about Prolog. I waited, and waited, and waited in vain for the other shoe to drop, thinking "well he must be coming to the subject of Resolution theorem-proving any moment now" but he never did. Instead he presented a version of Prolog that is quite unrecognisable by any working Prolog programmer, from the syntax, right down to the semantics; a version that only seemed to loosely share ideas like backtracking and pattern matching with Prolog. One-sided pattern-matching mind, not unification, because unification is, for some reason, really scary to Lisp and functional programming folks. A "Prolog" with the syntax of Scheme and with the semantics of Lisp variables and primitives like eval and so on. And when he was finally asked "how is real Prolog different" at the end of the lecture he said "because Prolog programmers have a really efficient interpreter". Meaning, I guess, the Warren Abstract Machine. Very disappointing.
marhee 16 hours ago [-]
Prolog is for logic what inverse kinematics is for robotics.
Where in imperative programming languages you supply arguments to a function and get a result in Prolog you can give the result of a function call and get all argument sets that lead to that result.
But you are right that in production systems you would seldom see Prolog, for reason that you can easily LLM.
bandrami 17 hours ago [-]
There was a neat helicopter landing game written in prolog way back in the day
cess11 5 hours ago [-]
Prolog is very succinct and interactive so it is quite nice for modeling and analysing problem spaces, similar to what you might do with Z3 or some other solver library.
Prolog also has exceptionally good string management through DCG:s. If you have a bunch of structured text and want to query it, Prolog allows you to do that. The syntax is very simple so you can even just sed your data into Prolog code and load that sometimes.
Supposedly SICSTUS Prolog is used in flight booking, and NASA did something with it sometime, but that's kind of obscure. If you ever need a rule engine, consider poking it with logic programming for a bit, perhaps it'll turn out both pragmatic and elegant.
fodkodrasz 16 hours ago [-]
Gerrit had an embedded prolog engine, and I recall branch protection rules / PR workflows were configured using progolog.
I used Prolog twice in production, but none of them were what I'd expect to be the "typical" uses.
1. I used GoLog (a Prolog interpreted in Go) for defining some functional tests in the project where the testing infrastructure was otherwise written in Go.
2. I used Prolog (SWI) to write a parser for Thrift (both the definition and binary format) simply because I needed one, and Prolog was convenient.
What I expect people who use Prolog for the stuff it's really good at is databases that encode some complicated business or legal processes. I.e. databases with many complex constraints that have to all somehow come together to produce a solution set. Prolog would also be a good language to encode / query graph databases. So, whatever you can think of being a good match for a graph database would also work well with Prolog.
There are also (even more niche) Prolog derivatives, eg. Ciao or Mercury, that are... well, decent all-purpose languages. You can just use them in the same context where you'd use Python or Haskell respectively. The implementations are pretty solid in terms of performance and correctness... so, if you like the approach, then why not?
ratew 15 hours ago [-]
[dead]
MikeNotThePope 17 hours ago [-]
I haven’t used Prolog, but I have a little experience with Erlang and a lot with Elixir. As I understand it, the early versions of Erlang were inspired by Prolog.
For those with familiarity with both Prolog and Erlang, can you comment on the similarities and differences between? Is/was Erlang basically Prolog with OTP bolted on?
- In Prolog next_light is database, in Erlang it's just a function
Question: What's the light before green?
% Erlang
% Returns actual value
prev_light_search() ->
[State || State <- [green, yellow, red], next_light(State) == green].
% Prolog (?- means that it's in query mode)
?- next_light(Light, green).
So syntax IS similar though the thing is that Prolog is more like binding and quering database and Erlang is executing function.
In a nutshell Erlang is more like: "when I have X, then I can calculate Y" and Prolog like "If I want Y, what's the X".
Antibabelic 16 hours ago [-]
Erlang has very little in common with Prolog, which is a language in an entirely different paradigm (logic programming).
Early versions of Erlang were implemented in Prolog, which is why Erlang's syntax looks a whole lot like Prolog's, but beyond that they're not very similar.
tannhaeuser 11 hours ago [-]
Not familiar with Erlang that much, but it's pretty clear Erlang was prototyped on Prolog because of its convenient facilities for DSLs using op/3 to define new tokens for its built-in bottom-up expression parser (using operator precedence parsing) and its Definite Clause Grammar recursive descent parser as trivial specialization of core SLD resolution (Prolog was created for NLP and planning apps in the first place after all).
I guess what may also have contributed is that there are a number of concurrent logics implemented in Prolog for prototyping Erlang's scheduler such as Concurrent Transaction Logic ([1]).
And to understand the four-port model is to understand solution-space navigation and pruning.
cwillu 23 hours ago [-]
It's why smartphones lost all their ports: forbidden knowledge must not be leaked to the public.
AdieuToLogic 22 hours ago [-]
> ... forbidden knowledge must not be leaked to the public.
Understanding is a personal achievement and has nothing to do with "forbidden knowledge" when the source of said knowledge is both quoted above and freely available.
cwillu 19 hours ago [-]
I fear that the joke didn't land with you.
AdieuToLogic 11 minutes ago [-]
It didn't and I am now doing a facepalm as penance. :-D
alecthomas 16 hours ago [-]
I found it very amusing :)
rtpg 1 days ago [-]
There's something quite illuminating with this first "horror", where they basically say "it's OK to report wrong answers, because you can check the answers".
I don't think I've ever felt like it's OK for my program to provide a list of answers where some are right and some are wrong, but reading this... and generally believing in P != NP.... maybe that's a decent way of looking at some stuff!
Zarathustra30 23 hours ago [-]
I've actually run into this in the wild, with regards to sales forecasting. A program we were using returned zero if the error bars on a forecast were over 100%. For example, selling somewhere between 1 and 7 units, but averaging 3.
Returning 3 was "wrong", but infinitely more correct than retuning 0.
taneq 13 hours ago [-]
That sounds like zero was meant to be treated as a special error value? If so then “bad forecast” is more correct than “everything’s fine here, situation normal”, no?
Of course this is far from the best way to do this.
cwillu 23 hours ago [-]
iirc, shor's algorithm for factoring relies on this.
DonHopkins 1 days ago [-]
Sometimes the Biorhythm program on my Apple ][ failed to produce correct answers. But it sure was great for impressing cool hippie chicks.
The article server is offline, but I assume they found out that prolog rule evaluation depends on the order the rules are presented in the program.
If so, the language they thought they were using (and that they should actually use) is datalog, not prolog.
Datalog has declarative semantics: All facts that are derivable from the base database and the rules will be derived by the interpreter, and it will not add extra hallucinated facts. If that's not true, it's a bug in the runtime, not in the language.
cbarrick 23 hours ago [-]
www.metalevel.at is run by Prolog legend Markus Triska, author of CLP(FD)/CLP(Z).
So it's not that they "discovered" anything about Prolog; they already knew the language inside out.
This article explains how to appropriately use Prolog declaratively and with full generality.
timonoko 7 hours ago [-]
We need infinity-Prolog, which already knows all known facts. Feeding them separately everytime feels lame.
alecthomas 16 hours ago [-]
I've never seen Prolog used at all in the wild, but OPA (and its ancestor, Datalog) are fairly common.
crustycoder 15 hours ago [-]
I get what he's saying but I think it's overstated. I'd categorise his list as "Things to be careful with" not "Coding horrors". For example, "The primary means to make your programs defective in this way is to use predicates like assertz/1 and retract/1" is an unqualified statement that makes it sound like you should never ever use them, and that's not the case. I have a real-life Prolog app that applies rules to facts read from JSON data files. I could do that two ways:
1) Read the JSON with Prolog (there's a library) and assertz() the facts from that, building an immutable database in the first phase before applying the rules in the second phase.
2) Externally transform the JSON into Prolog facts, load that into the app on startup and apply the same rules to it.
I agree that mutating the database in the second phase is probably a bad idea, but that's not the same as saying "assertz() always bad". I'd read his site before it appeared on HN and whilst there a lot of very good stuff on it, some of it reminds me of FP purist edicts - fine if you want to go that way and it's appropriate to your problem, but that isn't always going to be the case. That was the basis of my earlier (downvoted) "Mostly overblown" comment.
But nice to see Prolog mentioned at all on HN :-)
1 days ago [-]
pocksuppet 14 hours ago [-]
Would a Prolog expert please explain the difference between > and #>, is and #=, and what ! does?
The version without ! looks identical to the version with ! except only the ! is removed - is this a joke?
jodrellblank 8 hours ago [-]
Prolog operators like `4 > 5` are a syntax sugar which desugars into a normal function call `>(4, 5)`. This part of the language is programmable, so you can add your own function `#>(X, Y)` and then declare it as an operator and use it like `4 #> 5`. See [1]. Nitpickingly, this means we can't be sure what #> is without looking, but it's common in Scryer and SWI Prolog (at least) that the #> #< versions of numeric comparison operators are used by constraint solver libraries. In imaginary Python it might be this code:
:- using constraint solver library
X in 0..100,
X #> 50,
label(X)
where "in" and "#>" were added into the language at runtime by the import of the constraint library. That is, it calls out to a custom 'function' which tells the constraint solver to restrict possible values for for X from 0..100 down to 51..100.
> "and what ! does"
This is a concept which doesn't translate easily to other languages, but analogously it's like the performance difference between this code which always searches the entire haystack:
found = false
for item in haystack:
if item == 'needle':
found = true
return found
and this which stops searching the haystack if the needle is found, but still searches the entire haystack in the worst case:
for item in haystack:
if item == 'needle':
return true
return false
The catch being that ! is not exactly a performance thing, it's an instruction to the Prolog runtime to skip some of the code, which can speed up performance but if you throw it in carelessly, your code no longer gives the right answers.
[1] They aren't Prolog "functions", they are predicates, functions are different, but it will do for this explanation.
jfmc 12 hours ago [-]
!/0 is the cut. It prunes the search space. Useful to say "do not look at the other alternatives since I know they will fail" (when mutually exclusivity is hard) but also necessary to do negation in Prolog (when negated information cannot be easily or efficiently propagated).
is/2 is arithmetic evaluator. It runs only in one direction and it does not solve equations.
#>, #=, etc. are constraints, like (in)equalities over linear arithmetic. When constraints have the form of some known theory (like in SMT solvers), they can be solved (incrementally). That is called "constraint logic programming" (CLP). Modern Prolog systems are indeed CLP systems.
Prolog is older than CLP. CLP is older than SMT. Prolog+CLP systems are turing complete, can be used as programming languages. SMT is powerful but not a programming language.
Can "impure" features be avoided? Not in all cases. Think of them as 'unsafe' in Rust, but less dangerous.
Markus pushes for more purity in Prolog (using CLPFD), but sometimes some impurity (or imperative-like code with side-effects) is the best solution. Sometimes the pure solution is also the better. In other cases, it is not. Better compilers and static analyzers can reduce the friction between these worlds.
Take away: do pure code if you can afford it and it looks like a natural solution to your problem, use impure features later if you really need them.
crustycoder 11 hours ago [-]
I think in many real-life cases it's a mix - for example impure code that deals with the outside world to set up the data needed for the pure "core" of the app to run over.
>> The version without ! looks identical to the version with ! except only the ! is removed - is this a joke?
That's just showing getting rid of the cut in two stages. The line that makes it possible to remove it is this one:
N #> 0,
Markus Triskas' argument is that if you use the #> etc versions of declarative arithmetic operators, instead of the > ones, you can then call the factorial predicate with both arguments as variables, i.e. without inputs, just outputs, to enumerate the entire factorial relation. Like this:
?- n_factorial(N, F).
N = 0, F = 1
; N = 1, F = 1
; N = 2, F = 2
; N = 3, F = 6
; ... .
If you use > instead of #> the line N > 0 will raise an exception if N is a variable, which will be the case if you call it as above. This stops you from enumerating the relation, which declarative arithmetic allows.
Of course there are other ways to write a factorial predicate (or any predicate) so that it always enumerates a relation but they are more verbose. Then again, you do need a special library to use declarative arithmetic anyway, so.
YeGoblynQueenne 5 hours ago [-]
Well, with respect to Markus Triska, I don't like purity. Prolog gives you plenty of "impure" constructs like the cut (!/0) and the assert/retract family of database manipulation predicates. It also gives you impure I/O and arithmetic functions that are quite separate from the otherwise logical, declarative-ish style of the language.
I'm fine with all that. The language gives you sensible tools to deal with edge cases that otherwise require you to jump through hoops or import libraries (like the constraint arithmetic libraries that Markus recommends... and that he had to mostly write himself before he could recommend). You can get into a spot of bother if you use those facilities without knowing why they are there and why you shouldn't just spam them in every case, but that's why good textbooks exist.
And more to the point, that's why Prolog Coding Guidelines are a thing, more precisely, a paper, which you can find here from the website of Michael Covington who's one of its (many) authors:
Here's what the Guidelines has to say about assert/retract:
5.10 Avoid asserta/assertz and retract unless you actually need to preserve
information through backtracking
Although it depends on your compiler, asserta/assertz and retract are usually
very slow. Their purpose is to store information that must survive backtracking. If
you are merely passing intermediate results from one step of computation to the
next, use arguments.
If you have a dynamic predicate, write interface predicates for changing it instead
of using “bare” calls to asserta/assertz and retract, so that your interface
predicates can check that the changes are logically correct, maintain mutexes for
multiple threads, and so forth.
Sound advice. In fact that's what I've always done myself even before reading the Guidelines.
And here's some advice on using the "horror" of the cut without having to wake the Great Old Ones:
5.4 Use cuts sparingly but precisely
First think through how to do the computation without a cut; then add cuts to save
work. For further guidance see O’Keefe (1990, pp. 88–101). Concerning code layout,
make sure cuts do not go unnoticed: if a green cut7 may be placed on the same line
as the previous predicate call, red cuts definitely must be on their own line of code.
5.5 Never add a cut to correct an unknown problem
A common type of Prolog programing error is manifested in a predicate that yields
the right result on the first try but goes wrong upon backtracking. Rather than add
a cut to eliminate the backtracking, investigate what went wrong with the logic.
There is a real risk that if the problem is cured by adding the cut, the cut will be far
away from the actual error (even in a different predicate), which will remain present
to cause other problems later
Basically the message should be that we can help the novice to navigate the complexities of the language without underestimating or pataronising them. Cuts, asserts, and the lot, are just there to make things easier. They only make things harder when they're not explained properly. And telling everyone to just stay away from them is, I think, not the proper way to explain anything.
cess11 5 hours ago [-]
I kind of agree with both of you. I would have become better at Prolog faster if I had stuck to the discipline Triska promotes early on, but I also think the guidelines you cite are reasonable once one is starting to do somewhat productive work where compromises and speed factors in.
Over the years I've come to a similar position in other languages as well. If a functional-ish solution fits performance constraints and is maintainable, don't mutate or reach for global state, things like that.
18 hours ago [-]
txhwind 20 hours ago [-]
now we may have a more powerful "Prolog" - LLM Agent, though not precise and correct somtimes.
xlii 16 hours ago [-]
It reminds me of an old joke:
Radio Yerevan: A listener asks: "Is it true that in Moscow, on Red Square, they are giving away cars?"
Our answer: "Yes, it is true. Except it isn't in Moscow, but in Leningrad. And it isn't on Red Square, but on Palace Square. And they aren't cars, but bicycles. And they aren't giving them away, they are stealing them."
[0] https://www.complang.tuwien.ac.at/ulrich/prolog_misc/acomip....
There's TUI that allows querying of issues and the resource hierarchy. Issues can also be output as JSON which is fed into a LLM to produce cleanup actions and management reporting.
The Prolog app is very fast, considering what it's doing, largely because it makes heavy use of tabling so once an issue has been detected it's not recomputed when queries are made.
[1] https://web.archive.org/web/20190525163234/https://dev.to/da...
I have a application that has actions and actions can happen pretty much in any order. By default all scenarios should be an error except for ones that are in the boundary of logical steps, e.g.
Of course you can immediately see problem with this scope - what happens when non-logged-in user tries to upload or user logouts after upload etc.So I have ~50 actions, ~30 constraints which generate >200 scenarios which then are transformed into test suite.
Yet in short: Prolog is useful everywhere it's simple to express a rule but not that easy to implement it.
Users simply had to change the basic "facts" (who was available on what days, how many people were needed), and the program solved for the various constraints and offered solutions.
It was maybe about 300 lines of Prolog, no complex dependencies. It replaced a pile of Python scripts that required a lot of state, didn't really work, and could only run on a few specific computers.
For regular users, it was relatively easy to understand and change the facts. SWIPL for web also offers a nice "notebook" interface that lets you mix data, code, and markdown / output blocks so the documentation was inline.
Prolog also works extremely well as a target language for code generation by LLMs for these domains due to it being "higher up in the food chain" compared to procedural languages so to speak, and because Prolog was originally envisioned for classic NLP and hence has a corpus of one-to-one mappings from natural language to logic (as in the example in [3]). So well in fact that even with last-gen models textual descriptions for suitable problems become the bottleneck and you can in many cases just go straight to Prolog code instead ([2]).
[1]: https://quantumprolog.sgml.net
[2]: https://quantumprolog.sgml.net/llm-demo/part1.html
[3]: https://news.ycombinator.com/item?id=48080201
https://v3.yarnpkg.com/features/constraints
It never got released for good though. I actually had need of such feature for a project but I thought that using an exoteric programming language and an experimental feature was a bit much. I ended up setting up those constraints as a CI check hand-made script and the code was surprisingly large (~300 lines), but not that hard to understand.
This loops Prolog, but terminates in Datalog:
p :- p.
p.
?- p.
This is because the underlying mechanism is completely different. Datalog is like SQL with recursion, you start with known facts and repeatedly applies rules to derive all consequences until nothing new appears. In Prolog, you start from the query and works backward through rules until it either finds a proof or fails.
So, Datalog treats Horn clauses as database constraints/inference rules while Prolog treats Horn clauses as a search program. They use the same mathematical substrate, but completely different computational models.
- Datalog is a syntactic subset of Prolog
- Real Prolog implementations generally have the ability to configure their runtimes such that it becomes a proper superset of Datalog
[0] https://github.com/flix/flix
[1] https://github.com/rust-lang/polonius
[2] RDFox
[3] https://github.com/eclipse-biscuit/biscuit
[4] https://github.com/vmware-archive/differential-datalog [5] https://github.com/brurucy/pydbsp
[6] https://github.com/cozodb/cozo
But you can use it for lots of things. Whenever I'm frustrated with graph based tools being slow (like build systems), I run the graph through a datalog engine for comparison. It's usually much, much faster.
(This is also the problem with "I'll just quickly implement a Prolog-like DSL when I need it". Sometimes not a bad idea, but you have to be realistic. Your "lightweight" Prolog will be worse in every way compared to serious Prolog implementations).
Here[0] is an example of using Ruby and Prolog to solve a real-world AWS management problem.
0 - https://web.archive.org/web/20190525163234/https://dev.to/da...
https://t3x.org/lisp64k/prolog.html
The linked code runs in this: Unix, DOS and CP/M
https://t3x.org/klisp/index.html
It will compile for CP/M and DOS (Turbo C), Unix, Windows and whatnot.
64k Lisp:
https://t3x.org/lisp64k/index.html
Zenlisp it's similar but almost gives an intro CS course (pre SICP) for the cheap implementing discrete Math and tons of stuff in pure Lisp, even rational and complex numbers. The end chapter it's about logic programmer of course.
https://t3x.org/zsp/index.html
1: https://ds26gte.github.io/schelog/index.html
Like most "Prolog implemented in a LISP" examples, that's not Prolog. It's a Prolog-like LISP language that is missing the point. Implementing Prolog in Lisp is only "trivial" if you try to do something trivial and call it "implementing Prolog in LISLP", instead of actually, you know, implementing Prolog. In Lisp.
Since we're discussing an article by Markus Triska, and he's commented on the same thing, I'll let him do the honours:
https://github.com/triska/lisprolog
Some online books show how to implement simple "Prolog" engines in Lisp. These engines typically assume a representation of Prolog programs that is convenient from a Lisp perspective, and can't even parse a single proper Prolog term. Instead, they require you to manually translate Prolog programs to Lisp forms that are no longer valid Prolog syntax. With this approach, implementing a simple "Lisp" in Prolog is even easier ("Lisp in Prolog in zero lines"): Manually translate each Lisp function to a Prolog predicate with one additional argument to hold the original function's return value. Done. This is possible since a function is a special case of a relation, and functional programming is a restricted form of logic programming.
I'll just add that this idea of a "trivial" implementation of Prolog in Lisp seems to come from SICP which itself proudly shows off how to "trivially" do the job. I once sat through a couple of hours of lecturing on Logic Programming and Prolog by Gerald Sussman, on youtube, just to try and form a mental model of his mental model about Prolog. I waited, and waited, and waited in vain for the other shoe to drop, thinking "well he must be coming to the subject of Resolution theorem-proving any moment now" but he never did. Instead he presented a version of Prolog that is quite unrecognisable by any working Prolog programmer, from the syntax, right down to the semantics; a version that only seemed to loosely share ideas like backtracking and pattern matching with Prolog. One-sided pattern-matching mind, not unification, because unification is, for some reason, really scary to Lisp and functional programming folks. A "Prolog" with the syntax of Scheme and with the semantics of Lisp variables and primitives like eval and so on. And when he was finally asked "how is real Prolog different" at the end of the lecture he said "because Prolog programmers have a really efficient interpreter". Meaning, I guess, the Warren Abstract Machine. Very disappointing.
Where in imperative programming languages you supply arguments to a function and get a result in Prolog you can give the result of a function call and get all argument sets that lead to that result.
But you are right that in production systems you would seldom see Prolog, for reason that you can easily LLM.
Prolog also has exceptionally good string management through DCG:s. If you have a bunch of structured text and want to query it, Prolog allows you to do that. The syntax is very simple so you can even just sed your data into Prolog code and load that sometimes.
Supposedly SICSTUS Prolog is used in flight booking, and NASA did something with it sometime, but that's kind of obscure. If you ever need a rule engine, consider poking it with logic programming for a bit, perhaps it'll turn out both pragmatic and elegant.
[1] https://github.com/terminusdb/terminusdb
1. I used GoLog (a Prolog interpreted in Go) for defining some functional tests in the project where the testing infrastructure was otherwise written in Go.
2. I used Prolog (SWI) to write a parser for Thrift (both the definition and binary format) simply because I needed one, and Prolog was convenient.
What I expect people who use Prolog for the stuff it's really good at is databases that encode some complicated business or legal processes. I.e. databases with many complex constraints that have to all somehow come together to produce a solution set. Prolog would also be a good language to encode / query graph databases. So, whatever you can think of being a good match for a graph database would also work well with Prolog.
There are also (even more niche) Prolog derivatives, eg. Ciao or Mercury, that are... well, decent all-purpose languages. You can just use them in the same context where you'd use Python or Haskell respectively. The implementations are pretty solid in terms of performance and correctness... so, if you like the approach, then why not?
For those with familiarity with both Prolog and Erlang, can you comment on the similarities and differences between? Is/was Erlang basically Prolog with OTP bolted on?
- `;` in Erlang indicates multi clause function
- In Prolog next_light is database, in Erlang it's just a function
Question: What's the light before green?
So syntax IS similar though the thing is that Prolog is more like binding and quering database and Erlang is executing function.In a nutshell Erlang is more like: "when I have X, then I can calculate Y" and Prolog like "If I want Y, what's the X".
Early versions of Erlang were implemented in Prolog, which is why Erlang's syntax looks a whole lot like Prolog's, but beyond that they're not very similar.
I guess what may also have contributed is that there are a number of concurrent logics implemented in Prolog for prototyping Erlang's scheduler such as Concurrent Transaction Logic ([1]).
[1]: https://www.cs.toronto.edu/~bonner/ctr/Home.html
https://grack.com/writing/school/enel553/report/prolog.html
Understanding is a personal achievement and has nothing to do with "forbidden knowledge" when the source of said knowledge is both quoted above and freely available.
I don't think I've ever felt like it's OK for my program to provide a list of answers where some are right and some are wrong, but reading this... and generally believing in P != NP.... maybe that's a decent way of looking at some stuff!
Returning 3 was "wrong", but infinitely more correct than retuning 0.
Of course this is far from the best way to do this.
https://www.youtube.com/watch?v=jYoY1cwAd90
If so, the language they thought they were using (and that they should actually use) is datalog, not prolog.
Datalog has declarative semantics: All facts that are derivable from the base database and the rules will be derived by the interpreter, and it will not add extra hallucinated facts. If that's not true, it's a bug in the runtime, not in the language.
So it's not that they "discovered" anything about Prolog; they already knew the language inside out.
This article explains how to appropriately use Prolog declaratively and with full generality.
1) Read the JSON with Prolog (there's a library) and assertz() the facts from that, building an immutable database in the first phase before applying the rules in the second phase.
2) Externally transform the JSON into Prolog facts, load that into the app on startup and apply the same rules to it.
I agree that mutating the database in the second phase is probably a bad idea, but that's not the same as saying "assertz() always bad". I'd read his site before it appeared on HN and whilst there a lot of very good stuff on it, some of it reminds me of FP purist edicts - fine if you want to go that way and it's appropriate to your problem, but that isn't always going to be the case. That was the basis of my earlier (downvoted) "Mostly overblown" comment.
But nice to see Prolog mentioned at all on HN :-)
The version without ! looks identical to the version with ! except only the ! is removed - is this a joke?
> "and what ! does"
This is a concept which doesn't translate easily to other languages, but analogously it's like the performance difference between this code which always searches the entire haystack:
and this which stops searching the haystack if the needle is found, but still searches the entire haystack in the worst case: The catch being that ! is not exactly a performance thing, it's an instruction to the Prolog runtime to skip some of the code, which can speed up performance but if you throw it in carelessly, your code no longer gives the right answers.[1] They aren't Prolog "functions", they are predicates, functions are different, but it will do for this explanation.
is/2 is arithmetic evaluator. It runs only in one direction and it does not solve equations.
#>, #=, etc. are constraints, like (in)equalities over linear arithmetic. When constraints have the form of some known theory (like in SMT solvers), they can be solved (incrementally). That is called "constraint logic programming" (CLP). Modern Prolog systems are indeed CLP systems.
Prolog is older than CLP. CLP is older than SMT. Prolog+CLP systems are turing complete, can be used as programming languages. SMT is powerful but not a programming language.
Can "impure" features be avoided? Not in all cases. Think of them as 'unsafe' in Rust, but less dangerous.
Markus pushes for more purity in Prolog (using CLPFD), but sometimes some impurity (or imperative-like code with side-effects) is the best solution. Sometimes the pure solution is also the better. In other cases, it is not. Better compilers and static analyzers can reduce the friction between these worlds.
Take away: do pure code if you can afford it and it looks like a natural solution to your problem, use impure features later if you really need them.
https://www.swi-prolog.org/pldoc/man?section=clpfd-integer-a...
https://www.swi-prolog.org/pldoc/doc_for?object=!/0
That's just showing getting rid of the cut in two stages. The line that makes it possible to remove it is this one:
N #> 0,
Markus Triskas' argument is that if you use the #> etc versions of declarative arithmetic operators, instead of the > ones, you can then call the factorial predicate with both arguments as variables, i.e. without inputs, just outputs, to enumerate the entire factorial relation. Like this:
If you use > instead of #> the line N > 0 will raise an exception if N is a variable, which will be the case if you call it as above. This stops you from enumerating the relation, which declarative arithmetic allows.Of course there are other ways to write a factorial predicate (or any predicate) so that it always enumerates a relation but they are more verbose. Then again, you do need a special library to use declarative arithmetic anyway, so.
I'm fine with all that. The language gives you sensible tools to deal with edge cases that otherwise require you to jump through hoops or import libraries (like the constraint arithmetic libraries that Markus recommends... and that he had to mostly write himself before he could recommend). You can get into a spot of bother if you use those facilities without knowing why they are there and why you shouldn't just spam them in every case, but that's why good textbooks exist.
And more to the point, that's why Prolog Coding Guidelines are a thing, more precisely, a paper, which you can find here from the website of Michael Covington who's one of its (many) authors:
https://www.covingtoninnovations.com/mc/plcoding.pdf
Here's what the Guidelines has to say about assert/retract:
5.10 Avoid asserta/assertz and retract unless you actually need to preserve information through backtracking Although it depends on your compiler, asserta/assertz and retract are usually very slow. Their purpose is to store information that must survive backtracking. If you are merely passing intermediate results from one step of computation to the next, use arguments.
If you have a dynamic predicate, write interface predicates for changing it instead of using “bare” calls to asserta/assertz and retract, so that your interface predicates can check that the changes are logically correct, maintain mutexes for multiple threads, and so forth.
Sound advice. In fact that's what I've always done myself even before reading the Guidelines.
And here's some advice on using the "horror" of the cut without having to wake the Great Old Ones:
5.4 Use cuts sparingly but precisely First think through how to do the computation without a cut; then add cuts to save work. For further guidance see O’Keefe (1990, pp. 88–101). Concerning code layout, make sure cuts do not go unnoticed: if a green cut7 may be placed on the same line as the previous predicate call, red cuts definitely must be on their own line of code.
5.5 Never add a cut to correct an unknown problem A common type of Prolog programing error is manifested in a predicate that yields the right result on the first try but goes wrong upon backtracking. Rather than add a cut to eliminate the backtracking, investigate what went wrong with the logic. There is a real risk that if the problem is cured by adding the cut, the cut will be far away from the actual error (even in a different predicate), which will remain present to cause other problems later
Basically the message should be that we can help the novice to navigate the complexities of the language without underestimating or pataronising them. Cuts, asserts, and the lot, are just there to make things easier. They only make things harder when they're not explained properly. And telling everyone to just stay away from them is, I think, not the proper way to explain anything.
Over the years I've come to a similar position in other languages as well. If a functional-ish solution fits performance constraints and is maintainable, don't mutate or reach for global state, things like that.
Radio Yerevan: A listener asks: "Is it true that in Moscow, on Red Square, they are giving away cars?"
Our answer: "Yes, it is true. Except it isn't in Moscow, but in Leningrad. And it isn't on Red Square, but on Palace Square. And they aren't cars, but bicycles. And they aren't giving them away, they are stealing them."