I have a long standing love affair with Prolog and frustration for its failure to grow. Prolog has poor features for abstraction and is actually not declarative enough!
Prolog's limitations can be great for starting to get the paradigm but then you hit a wall. (Kind of like standard Pascal!)
Mercury and Curry fix some of these limitations as does miniKanren. Integrating CLP is important yet so far always clumsy as standard Prolog provides no way to reify the environment.
Respectfully have to disagree. Prolog has the best features for abstraction of any language I've used, I suspect it may be near an optimal fixed point for metaprogramming expression[3]. I will say the other side of that wall is breathtaking.
Also not sure what you mean, CLP is a first class consideration in many Prologs, esp Scryer Prolog. Check these crazy demos out:
Prolog predicates are not first class values. Data structures are not abstract. Compare both with any modern lisp or better with functional languages. Mapping and filtering is awkward. Arithmetic is awkward. Indexing and search strategies are not under programmer control. Modes are awkward. Cut and dynamic assert of global facts are abominations which undermine logical reasoning. Prolog programmers often write metacircular interpreters to fix these problems which is wonderfully easy but kills efficiency. The CLP examples aren't integrated with Prolog's Horn clause resolution model, they're just libraries with strange semantics. I've been an enthusiastic Prolog programmer since the mid 1980s, attended lots of conferences, read lots of papers, etc. There have been many promising attempts to fix these problems but they've only shown up as non-standard features in specific implementations. It's similar to the "curse of Lisp" - everyone does their own thing and no consensus emerges to move the standard forward. But it could be worse if the standard were "feature oriented" rather than eliminating the limitations and flaws by cleanly generalizing the model. I study new logic programming languages avidly hoping to see a worthy successor to Prolog. So far none quite make it. Mercury might do it if it got more love.
> There have been many promising attempts to fix these problems but they've only shown up as non-standard features in specific implementations. It's similar to the "curse of Lisp" - everyone does their own thing and no consensus emerges to move the standard forward.
> But it could be worse if the standard were "feature oriented" rather than eliminating the limitations and flaws by cleanly generalizing the model.
Why do you feel that "eliminating the limitations" is the way forward, and not standardizing common tasks instead, making them ergonomic, uniform, fast?
I don't think that more power can lead to those. Maybe ergonomics and uniformity can happen by accident if a library emerges as the default option for a task, but speed, I don't think it can.
A lot of these comments don't make any sense to me.
> Prolog predicates are not first class values.
Predicates are trivially called, even as variables, with the `call/N` metapredicate.
> Mapping and filtering is awkward
In what sense? The declarative semantics...?
> Arithmetic is awkward
In what sense...? Have you seen clpz?
> The CLP examples aren't integrated with Prolog's Horn clause resolution model
In what sense...? clpz and clpb do this magnificently.
> Indexing and search strategies are not under programmer control.
Most ship with SLG resolution or you can write your own resolution strategy with a simple metainterpreter as an intermediate exercise -- but SLD resolution is already pretty good. In general not needing to think about the indexing and search strategies are a highlight of the declarative semantics of Prolog, its odd to see someone with a "long standing love affair with Prolog" list this as a drawback.
> Modes are awkward.
Modal programming is a defining feature of Prolog. Tell me more about this "long standing love affair", again?
> I've been an enthusiastic Prolog programmer since the mid 1980s
If you are still struggling with mapping, filtering, arithmetic, `call/N`, and CLP in Prolog after nearly 45 years of "enthusiastic" programming, I'd highly recommend checking out Triska's Power of Prolog videos for some guidance, I think you will find them very illuminating.
> Predicates are trivially called, even as variables, with the `call/N` metapredicate.
Yes, that is the definition of "predicates are not first class values". Some things can be called without call/N. Other things can not be called without call/N. These are two separate classes of things. Both of these classes cannot be the first class.
I think there is some confusion around what is "first class" in Prolog. Any syntactically valid construct in (ISO-conforming) Prolog is "first class", including the symbols that are the names of predicates. The fact that Prolog is a homoiconic language makes any valid Prolog code "first class".
"First class" meaning, can be the arguments to a predicate or processed as data.
Predicates (and only predicates) can be called with `call/N` -- although you could write a meta-interpreter with different properties. You could pass in the number `1` and call a randomly determined predicate, as an absurd example.
Perhaps you mean, "the head and body of a predicate are not first class" ? This again is false. They are valid data and can be processed as such -- please see [4] for clarification.
Perhaps you mean "they cannot be looked up dynamically at runtime" -- this is also false, please see [3].
Are there other eligibility requirements for "first class" that we should discuss?
First of all lets be clear: the concepts of "first class" and "callable" are procedural terminology coming from object oriented and functional languages. I am admitting them to the discussion for purposes of comparative language analysis. My criteria is "if a reasonable
person would recognize a language construct in Prolog as similar to an equivalent language construct in an OO or FP language, we can discuss it as if it were the same".
However, this is a charitable
interpretation that is open to abuse if desired.
It is starting to sound like the criticism is that Prolog is not an object oriented programming language and does not pass contextual object information along with symbols in the same way SICP-style higher order functions are treated in functional
programming languages.
This is by design, Prolog is a logic language that describes relationships, not a procedural language.
There is no behavioral difference that distinguishes a Prolog predicate as not "first class". There are many metapredicates designed to accept predicates as arguments, such as maplist/N. This is the primary criteria for supporting first class "callables" (another word poorly suited for Prolog, but I'm admitting it for purposes of conversation) in other languages. I would have assumed that would be a sufficient behavioral affordance.
> there are first-class callable things and second-class callable
things
To make this more concrete, please provide some examples of "first-class" and "second-class" "callable things" in Prolog, as well as an example of "first class" and "second class" "callable things" in another language.
Given your level of confidence in your argument, I assume this should be fairly easy to do. Then we might have a concrete basis for discussion.
I really don't care what you "admit". Now you're saying that it doesn't matter whether Prolog has predicates as first-class values, and yet you keep arguing that it does have them. I don't think you're here anymore to establish what statements about Prolog are true or false. You're here for a fight; I'm not here for a fight. Go fight yourself.
Not for you, but purely for the benefit of unfortunate souls who wander by and are confused what there is to argue about:
This predicate calls some other predicate `call_direct/2` in a first-class way. It's a call.
It also calls some predicate identified by whatever the variable IndirectCallTarget may be bound to. This is a second-class call. It's frequently referred to as a "meta-call" to signal that it's not a first-class call. It's important to note that the value passed in for the IndirectCallTarget parameter is not a predicate. It cannot be, since there are no predicate values in Prolog. It's the name of a predicate. (Plus maybe a partial argument list; still not a predicate.) Since the thing being meta-called is not a predicate, it must be meta-called specially using the `call/N` builtin. The user has no realistic way of implementing the `call/N` builtin themselves.
> The user has no realistic way of implementing the `call/N` builtin themselves.
Not sure what you mean by realistic, but `call/1` can be implemented by having one simple rule for each existing predicate (now for the sake of the argument ignoring control constructs, which require somewhat more complex processing first) plus a rule for uninstantiated variables and one for an inexistant predicate. And `call/N, N > 1` can now be defined based on it.
Yes, enumerating all predicates in the system and meta-interpreting all control structures seems unrealistic to me. In the sense that no Prolog application developer (as opposed to a Prolog system implementor) would want to do it. Except maybe as an intellectual exercise.
Of course you wouldn't really need to enumerate all predicates in the definition of call/1. You could first run a whole-program abstract interpretation to identify just the ones that can actually be meta-called. Much more appealing :-)
Yes, this technique has been used by several implementations. And any application developer can use `asserta/1` for the very same purpose. Just one rule, that is certainly much more appealing.
I see we are at an unfortunate impasse. I assert what you are calling a "second-class call" is usually considered "first-class". I will leave the definition here for readers to decide for themselves. I rest my case and wish you a good day.
> Higher-order functions: passing functions as arguments
Further information: Higher-order function
In languages where functions are first-class citizens, functions can be passed
as arguments to other functions in the same way as other values (a function
taking another function as argument is called a higher-order function). In the
language Haskell:
map :: (a -> b) -> [a] -> [b]
map f [] = []
map f (x:xs) = f x : map f xs
Not specifically aimed at this comment, but it looks like in most Prolog threads here, many commenters seems to plugging in Scryer Prolog, but perhaps, SWI is the most 'batteries included' and mature Prolog implementation for people not familiar with Prolog to try out .
There is a bit of... let's say friction between Markus Triska (Scryer) and Jan Wielemaker (SWI), I seem to remember. The SWI people are much less attached to ISO Prolog (i.e. prone to experiment with non-ISO syntax), and some things that are fixed in the SWI implementation impeded the realization of M. Triska's projects. Generally, people tend to like the new and shiny but there's also a significant philosophical gap between Scryer and SWI.
Now why would syntax be that important? It's because it directly enables homoiconicity, which is central to Prolog metaprogramming features: executing Prolog code returns a Prolog term, that can be read (just like Lisp). This is the distinctive characteristic of Prolog compared to more mainstream solvers, and what makes it 'a good programming language because it's a very dumb theorem prover'.
Wot. SLD Resolution is a "very dumb" theorem prover?
SLD Resolution is sound and refutation-complete and it is the basis not only of Prolog but also the most successful bunch of SAT solving algorithms in the last, dunno, several decades.
SLD-Resolution is sound and refutation-complete (and also complete with subsumption). If you think that O'Keefe is right to say that it's a "very dumb theorem prover" then explain to me why _you_ think so, not who said it.
Because I, too, can quote you authorities- and probably bigger than O'Keefe.
Not an appeal to authority. Just showing that quote wasn't of my invention. I don't really get why you're so riled up. I'm not saying SLD resolution is dumb, just that Prolog stays simple by not including all the clever heuristics and circumstantial techniques of other solvers. Which is a big part of what makes Prolog a nice programming language. It's more a compliment than a critic, really!
I'm not riled up, I even upvoted your OP, but it's uncouth to drop a quote without any context as a reply to a comment. Of course there's going to be misunderstandings.
I didn't remember that quote from O'Keefe. Prolog is indeed not trying to be smart and SLD-Resolution is dead simple - it's a sound and complete deductive inference system with a single rule. The reason Prolog is in turn so simple is because, thanks to the refutation-completeness of SLD-Resolution, you can implement it as a Depth-First Search for resolvents and then spam it until you get a result (or until you hit an infinite branch... oops). That's certainly orders of magnitude more simple than every other solver or automated theorem prover out there, like you say.
If that's what O'Keefe means, that Proolog is not trying to be smart, then OK, but that's not dumb. Every other solver tries to be smart and ends up having to solve an unsolvable problem. Who's dumb now then?
But maybe that's the compliment, I don't remember the context of O'Keefe's comment. Was it in the Craft of Prolog?
TBH, I don't remember where I first read it, but it's all over the web xD. This is all just a misunderstanding: since I knew you were a Prolog expert, I assumed you would recognize my (botched) quote and the context. Yeah, I understand it as: 'better to keep it simple and understandable'
SWI Prolog 7 added "X = Dict.key" syntax and that use of "." makes it fundamentally incompatible, ISO standard breaking, backwards incompatible to previous Prologs, sideways incompatible to other Prologs.
This is a worse sin in Prolog than it seems at a glance, because one of the strengths Prolog has is code-is-data / data-is-code metaprogramming. That includes exporting code as Prolog terms (use cases you might use CSV or JSON for in other languages), reading them back in as Prolog data (perhaps in a different Prolog system or different version) and executing the data as Prolog code. With that "." syntax change no other Prolog system can guarantee to read all SWI Prolog code, SWI 7 can't guarantee to read all SWI 6 code, and SWI 6 can't guarantee to read all SWI 7 code.
Code might say "connect_to_mongodb()" and you don't have mongodb in your system so you cannot run it, but you can read the code in as data and it will parse, just like reading in JSON which has a string mentioning some library you don't have; you can still introspect it and write reports like "what names does this data reference?", you can transform it and export it, or pass it through untouched. With SWI's new dot syntax the code might not parse at all, like an incompatible proprietary JSON syntax where you can't even import it. Code written 30 years ago which uses the dot in the old standard way might trigger SWI to try and read it in the Dict.key way and fail. Code exported from SWI 7 might include this syntax which other systems can't import.
I don't know how often it will come up in practise, but it seems that SWI could have done it with a slightly different syntax that would have been as convenient to use and also been a standard term and wouldn't have made this split at all. SWI has some other differences versus ISO Prolog, things inside error handling, for example, but none quite so fundamental as this. And it's annoying from the outside because you can wade into a big-ball-of-mud design-by-committee language, but if you want to look at an esoteric language and they're all arguing over who is most pure and virtuous you have to pick a religion before you can write Hello world.
Markus Triska's Power of Prolog series has been some of the best Prolog publicising material in years, something that isn't (totally) a dry academic text of "a --> a | a. a(A) :- a([a|As]) , a(As).", it must be a huge amount of work on his part. He uses and contributes to Scryer Prolog, and he is especially interested in Constraint Language Programming which he wrote/maintained in SWI[1], and has moved the newer versions to Scryer.
That said, I strongly agree with your comment, SWI is batteries included, it has lots of builtins, a packaging system to download and install modules, it has a debugger and graphical debugger and tracer and just a ton of decades of development and polish that Scryer hasn't had time to develop yet, and is much much friendlier for people not familiar with Prolog to try out. You have to be pretty hardcore to be writing Scryer Prolog in EMACS buffers with no predicate search, no help, limited libraries, limited documentation, limited debugging, very small online community even by Prolog standards which is already small.
When you could open https://swish.swi-prolog.org/ and click 'new Program' and as a beginner be able to write syntax highlighted code in browser with no download, no setup, no install, no account registration, but it's SWI Prolog.
Query "apropos(string)" in the query box in the lower right and see things like "string_lower/2" and "string_concat/3". That search is convenient and those predicates are SWI custom ones.
Query "help(format)" and see HTML styled, coloured, scrollable help for the text formatting domain specific language. That's enormously useful.
The Power of Prolog series is great and what Markus is doing is vital: We must teach that Computer Science is not an exotic, marginal way of approaching software development, but the foundation that we constantly draw upon and inhabit.
I don't know if they could do a try/fallback or if one is available as a setting (I haven't looked), but apparently they don't by default; Scryer Prolog:
?- X = '.'(1,'.'(2,'.'(3,[]))).
X = [1,2,3].
SWI Prolog 9:
?- X = '.'(1,'.'(2,'.'(3,[]))).
ERROR: Type error: `dict' expected, found `3' (an integer)
All of what you say is true, and yet practical applications that did break are somehow not talked about quite as much as hypothetical applications that might have broken. SWI could reuse infix dot precisely because it was universally considered bad style to use it in the old style, and hence was not used in the old style.
Which is not to say that I think the record syntax is particularly useful. But I wish not every Prolog discussion devolved into "Markus Triska fanpersons regurgitate walls of text about infix dot".
I wish not every Prolog discussion had a top comment about Mercury, Curry, Minikanren, et al; but I think you missed the end of my comment where I recommended SWI over Scryer for most people; I am unashamedly a Markus Triska fanperson but that doesn't mean I do everything he does, or that I subscribe to ISO Purity over all else. It was more that the parent comment claimed a "friction between two people" and I think that's unfair and leaves readers expecting soap opera drama where someone insulted someone's mother; whereas it is a difference of opinion about language compatibility and standards - and once you know that you can decide whether it matters to you and your potential use cases (which, again, it doesn't to me and I think it doesn't to anyone who hasn't touched Prolog before).
I am not aware of any practical applications which have broken, but then I'm not aware of anyone using Prolog for anything, anywhere.
> I wish not every Prolog discussion had a top comment about Mercury, Curry, Minikanren, et al
Absolutely. Datalog too.
> but I think you missed the end of my comment where I recommended SWI over Scryer for most people
I did not miss that. I have no complaints about that part of your comment. I complained about the prologue to it, which I thought was beside the point and devalued the whole thing.
> but then I'm not aware of anyone using Prolog for anything, anywhere.
>> Code might say "connect_to_mongodb()" and you don't have mongodb in your system so you cannot run it, but you can read the code in as data and it will parse, just like reading in JSON which has a string mentioning some library you don't have; you can still introspect it and write reports like "what names does this data reference?", you can transform it and export it, or pass it through untouched. With SWI's new dot syntax the code might not parse at all, like an incompatible proprietary JSON syntax where you can't even import it. Code written 30 years ago which uses the dot in the old standard way might trigger SWI to try and read it in the Dict.key way and fail. Code exported from SWI 7 might include this syntax which other systems can't import.
So just write a translation layer, or add some flags to your Prolog so it can parse SWI's syntax. SWI does that (it has flags to adjust itself to other Prologs' syntax). Do other Prologs do that? Not to my knowledge, but why not? It's no big deal and certainly not a big enough deal to cleave a rift in the Prolog community, as if it wasn't small enough and dwindling already. I think some people have convinced themselves it's "better to be first in the village than second in the city" and they just don't want to work with others.
And as it sounds like you probably know, SWI is by far not the only Prolog to commit that cardinal sin of breaking portability. Basically every Prolog ever does that. Every single one. The ISO standard is just as opinionated as everybody else about what Prolog should be like (and btw ISO is not Edinburgh, let's not forget- and who came first, huh?) except it has delusions of grandeur because ISO.
I will take batteries included over nose-in-the-air "we have strict adherence to standards" any day.
> "cardinal sin of breaking portability. Basically every Prolog ever does that. Every single one."
Indeed; still Markus Triska speaks positively about, and recommends, different Prolog systems. He seems to prioritise things above ISO purity, and is not king of the hill of Scryer Prolog[1], he doesn't comment like others who act as if "the village and city can burn to the ground for all I care, heresy against ISO Prolog is NEVER acceptable". So when he's finding this objectionable even after considering that, it seems reasonable for me to weight it more strongly. It's not enough to make me stop using SWI, or stop me recommending it (as I did above).
The lack of portability is a bad problem in the Prolog world and it has bit me a few times, but surely the solution is for all the implementers to work together, rather than engage in petty feuding.
But the biggest problem of the Prolog community is what I pointed out above: there's very few of us and the field isn't really growing much.
My little pet peeve with prolog is the lack of context parameters (which can be thought as a type of abstraction).
For example, imagine I'm writing a maze solver. The maze solver predicate receives obviously, but it has to pass as a parameter the maze again and again to all sub-predicates. There is no concept of "current maze", like in OO you would have with this.maze, or in Haskell you would do with a reader monad. As a result, all the "internal" predicates in a module get full of parameters all they do is pass around until some final predicate uses it to do some calculation.
Either that or you do the assert/retract dance and now you have bigger problems.
Quantum Prolog has this feature where you can query against a dynamic database, not just the global default database; ie. where in regular Prolog (and in Quantum Prolog as well of course since it's full ISO) you query
p(a).
p(b).
?- p(X)
you can instead query
KB = [ p(a), p(b) ],
KB ?- p(X)
introducing a clause-list as first parameter to "?-".
In the description [1], this is used to avoid destructive database manipulation via assertz/retract builtins, and thus to allow much more complex combinatorial planning problems and action post-conditions to be solved/optimized without resorting to ad-hoc hacks. But you can also use this for mere convenience in large knowledge graphs, and a technique very similar to it, albeit implemented in Prolog itself and not provided with native speed, has been used as a historic extension to Prolog DCG parsing (cf. definite-clause translation grammars by Dahl et al).
There are multiple ways to accomplish this, but the one that is the most straightforward is to simply make an object mapping of the type you are familiar with via AVL trees[1]. Easy way to get the "this.maze" semantics. You can get global context and local context via "blackboard"[2] semantics.
However quite frankly the most powerful way to do this is not obvious because it doesn't translate well to other languages: meta-interpreters[3].
For [1], you would either need to pass the AVL tree around or to have it as a global (which is not wanted), and instead pass the key (the "this" context which is different for different mazes) for the context around.
For [2] again you have a global table (with copying semantics as for assert/retract? or maybe without copying? the docs don't say). But again you would need to pass a key around.
[3] is... yeah. I mean, sure, you could demonstrate this with a toy metainterpreter on a toy example. But do you really want to run your whole application inside a metainterpreter?
One could also abuse DCG syntax, with the context being some state object instead of a DCG list.
A more practical way would be Logtalk-like code generation. The most practical way would be actual Logtalk. Unfortunately, last I heard Scryer refused to host Logtalk for no real reason.
> For [1], you would either need to pass the AVL tree around or to have it as a global (which is not wanted), and instead pass the key (the "this" context which is different for different mazes) for the context around.
Not sure how tracking references is different here than any other programming language. Passing objects around is pretty common in OO programming. An AVL tree is just the underlying abstraction used to implement the object. You don't have to implicitly supply the "this" parameter to each "object" predicate if you don't want to -- you could insert that yourself via compilation (with term/goal expansion)[4] or interpretation (via meta-interpreters) if you were really interested in that level of syntactic sugar.
> For [2] again you have a global table (with copying semantics as for assert/retract? or maybe without copying? the docs don't say). But again you would need to pass a key around.
You could use global or local semantics as desirable. The blackboard has a global version that is persistent across application state or a local version that provides lexical context which unwinds on backtracking. Not sure how "passing a key around" is different than most other forms of programming, but if you wanted to compile it away, please review the techniques listed above.
> [3] is... yeah. I mean, sure, you could demonstrate this with a toy metainterpreter on a toy example. But do you really want to run your whole application inside a metainterpreter?
A "toy" meta-interpreter? Meta-interpreters are as fundamental to Prolog as for-loops are to Python. Certain applications, such as games, are run "entirely inside a loop", so I'm not sure how this criticism applies. You can run as much or as little of your application inside a meta-interpreter as you want. The value proposition of Prolog is that the simple homoiconic syntax allows for powerful meta-interpretation. I'd suggest checking out the video I linked to in [3] if you have doubts on that topic.
> One could also abuse DCG syntax, with the context being some state object instead of a DCG list.
State transitions (a sequence of states) are a great use for DCG syntax! I wouldn't call that "abuse".
> A more practical way would be Logtalk-like code generation. The most practical way would be actual Logtalk.
If you are willing to give up the most powerful features of Prolog, sure.
> Unfortunately, last I heard Scryer refused to host Logtalk for no real reason.
> You don't have to implicitly supply the "this" parameter to each "object" predicate if you don't want to [...] if you were really interested in that level of syntactic sugar.
>>>> There is no concept of "current maze", like in OO you would have with this.maze, or in Haskell you would do with a reader monad. As a result, all the "internal" predicates in a module get full of parameters all they do is pass around until some final predicate uses it to do some calculation.
I would say that yes, the OP wanted exactly that level of syntactic sugar and your previous suggestions [1] and [2] were addressing something else entirely.
> you could insert that yourself via compilation (with term/goal expansion)[4]
Yes, that's why I meant above by "Logtalk-like code generation". Suggesting that I study the thing that I suggested feels a little condescending.
Yes, the OP is probably unaware of the recent advancements in Prolog. There is a set of techniques using pure Prolog that have made the language incredibly powerful compared to the techniques of the 80s and 80s. The more we use the abstract features of Prolog, the more powerful it becomes.
The declarative expression of the problem is elegant but even if this toy example is successfully resolved, make it a little more complicated and you'll have the interpreter ping-pong between two states infinitely.
As I see it. Prolog as a language and idea is great but the existing solvers are useless for any real problem ... or you'll have to resort to cuts and memorizing states and at least partially implement an imperative solution that you yourself have to come up with. And that's totally killing the magic.
Well, I mean... Prolog is an implementation of 1st order logic with syntax sugar. So basically, Prolog is incredible if your problem can be expressed within the framework, but less so if it can't. That's pretty much why there were extension attempts such as lambda Prolog.
you're simplifying the practicalities of prolog. there are many problems that you can express declaratively to the t. and yet many (all?) solvers aren't able to reduce it to a solution. the search isn't even successfully brute forcing - it will get stuck in some branch and switch endlessly between its leafs. and then it's up to you to figure that out and help the solver. even then prolog has its value but it fails at delivering the primary promise: you describe the problem, it finds a solution.
That's the oldest complaint in the book about Prolog: "it's not 100% declarative". OK. So use Java. Or C. You think you'll have more declarative fun writing a Zebra Puzzle solver in C, than in Prolog? Be my guest.
No, the truth is that Prolog is a unique language that is almost perfectly poised between the two extremes of beautiful but unusable formal purity and everyday programming utility. Prolog makes pragmatic choices when it has to and chooses to sacrifice declarative purity for the sake of performance and usability, because that's the only thing that makes sense considering that we have to run our programs on real computers, programmed by real programmers.
And then people complain that it's no good because you can't write a solver in a purely declarative form, even though you can't even get close to the declarative features of Prolog in most other languages; except ASP, which is so declaratively pure that it doesn't even have lists.
That's just a very poor criticism, poorly thought out and really meaningless in practice.
I'd say Prolog delivers in a (relatively wide) subset of its domain of application. For instance, I'm writing a solver for some common issues in epidemiology, at the moment. I was able to write a fully declarative (and purely relational) solution! But yes, some applications are better suited than others.
Well, that's why language paradigms are a thing - if you are not familiar with any language in the logic paradigm but are an expert in the OO-paradigm, this could take a little bit to wrap your head around. Triska is an excellent teacher of Prolog, be sure to check out his videos linked.
You have "Rows" repeated eight times in this short snippet. You have all the rest of your variables as two letter names. It feels low level, almost like Fortran.
That's actually what this article presents as its strength and simplicity. The straightforward choice in Prolog is to use global "who may do what" tables. In contrast, the author overengineers a Kotlin solution and then says "look, this is overengineered". I think global tables would make the Kotlin code half as long and much simpler too.
> Mercury and Curry fix some of these limitations
At the cost of introducing new ones. Mercury makes it effectively impossible to pass around partially instantiated structures.
By allowing you to use the features of the host language to complement the features of miniKanren. Having good support for multiple programming paradigms is better than trying to make one paradigm fit all needs.
Poplog[1] was an earlier attempt to provide such synergies but it failed to gain market share. It's now free software so take a look!
The Racket ecosystem is another approach where each module can choose a language with some of them being Prolog-like[2].
[1] https://en.m.wikipedia.org/wiki/Poplog
[2] https://racket-lang.org/languages.html
Ok, but MiniKanren isn't intrinsic to Scheme. I agree Racket makes it especially easy to embed sub languages, but you could embed core relational Prolog just as well as MiniKanren. My understanding of your statement is that Scheme and MiniKanren share sexp syntax, but the same applies: you could embed an sexp-based Prolog just as well. The only remaining MiniKanren advantage is then to have a complete search strategy, this I concede.
In a long forgotten past a large part of my graduation was Prolog (I was as far ahead then as i'm behind now with the ol' AI thing; I worked on mixing neural nets, reasoning with uncertainty with Prolog at the time) and, after hallucinatory episodes living, sleeping, (day)dreaming in Prolog for months on end, when something was finished I was always so surprised how clean, readable and 'too little' the code looked for what it did. Once you really grok it, it's a magic tool. I replaced it with Common Lisp after (in my uni, there was no mention of Lisp; we didn't even know it existed basically besides some weird scribbles in papers which were easy enough to study so we didn't give it more thought) and have the same feelings/experiences there but CL is usable for basically anything, including logic programming.
...like writing a whole web app in prolog sounds terrifying (same as writing a whole web app in regex), but recognizing and having some excellent interop between "modes" is obviously useful for regex, sometimes sql is supported in other languages, but even with the usefulness of prolog outcomes, there's almost never been that convenient "this section is logic" in the same way that we've universally adopted "regex" for string matching.
It's been a while since I used it, but look at the miniKanren implementations for your favorite programming language (js in your case, but there are a lot). It's basically a stripped-down version of logic programming.
I started learning prolog just a few months ago, when I stumbled upon https://linusakesson.net/dialog/ which is a spin on prolog optimized for writing interactive fiction.
I terms of Prolog implementations I played a bit with https://www.scryer.pl but it still feels rough around the edges.
SWI-Prolog is the most popular and most batteries included Prolog: https://www.swi-prolog.org
With its libraries and documentation it is a very practical language. What surprised me is, that you can easily produce amazingly small stand-alone binaries.
I read about dialog in another HN thread a few weeks ago. Between then and now I've had the itch to write some interactive fiction, but I could not for the life of me remember the name of that project.
> The reverse predicate from this section should not be used in practice - most Prolog implementations actually provide a built-in version which is a lot more performant than our implementation.
That feels like cheating. If you shouldn't use the implementation shown, then why do you even show it? Let us see the performant version!
That's like Haskell's quickSort implementation in a couple of lines... beautiful but horrendously non-performant as it doesn't actually implement the algorithm, it just implements the "idea" (while losing all the performance of the actual algorithm, which requires in-place mutation).
No built-in is needed for an efficient reverse. It's just one or two lines longer because you need to write a tail-recursive helper with an accumulator, same as in functional languages: https://stackoverflow.com/a/74777180
I always enjoy reading positive pieces about Prolog but without touching on the implications of the principles on display, this article may do more harm than good.
You would ask reasonable questions like, "for God's sake, why?". It feels like you wouldn't use Prolog for anything besides an intellectual game.
Regarding the why:
Some of those reasons include Definite Clause Grammars, Meta-Interpreters, 1st class constraint logic programming, reified conditionals, and term/goal expansion.
There are a lot of exciting modern advances with Prolog, especially Scryer Prolog.
And this is nothing new. People already knew how to write compilers in Prolog (easily) in the 90s. The problem with Prolog is that it requires a change in the way you think about problems, to a more declarative way. Programmers are in general not willing to do this since the result will be not as performant as what they can do with C. There must be a revolution in programming education and tools before people fully understand how Prolog works.
"since the result will be not as performant as what they can do with C" -- This isn't the main reason, but it's also not really true. Paradigm changes don't imply "less performance". To the extent programmers believe, herd-like, "C is fast therefore my program will be fast", they are almost always wrong.
A lot of programmers resist learning anything new, for various reasons, but most charitably because they are never exposed to new ideas or paradigms.
yeah yeah i got that too after a while, which is also why i like non mainstream programming languages, after a while you're tired writing more versions of the same routines/procedures/methods that won't help you find better solutions
> Datalog is a declarative logic programming language. While it is syntactically a subset of Prolog, Datalog generally uses a bottom-up rather than top-down evaluation model. This difference yields significantly different behavior and properties from Prolog. It is often used as a query language for deductive databases.
do you know what you are writing about? I mean have you actually done something with datalog? and then _which_ datalog? if yes, then you are probably someone working with it academically or the answer is no. because try to even set a toy project up with it (for the purpose of learning how to use it) and you'll quickly run into unmaintained interpreters, discussions of what datalog is and what not and you can choose between difficult to understand academic papers or simplistic introductions that lead you no where.
I have found two somewhat usable (your point still stands): soufflé (high performance but more limited) and DES, which works well for some simple personal data management, after some code massage (it’s written in Prolog). Any other recommendations? And since the prolog experts are here: what do you think about Ciao? Seems quite polished but also adventurous to (non-expert) me
Ok just to clarify, Datomic is a Clojure thing. It is free to use but closed source. It is an excellent database that is used, owned, and financed by Nubank, the largest and most rapidly growing bank in Brazil.
It is not Datalog syntax but heavily inspired by Datalog.
I'm throwing this in here just for clarification, I don't want to see Datomic as collateral damage
in this conversation.
Datascript is very similar to Datomic, except that it runs in ClojureScript and is an in-memory datastore with no concept of history or point-in-time queries. The schemas are also much looser than Datomic.
Otherwise, many syntax and semantics are similar.
No dependency on Datomic as Datomic is Java and DataScript is JavaScript.
I tried using Datomic Pro for a CMDB. I liked how logical queries were but I ended up going with Neo4j instead because finding paths between two nodes is incredibly useful in IT.
I'm fully aware they are very different things. I'm just saying I have tried using datomic and I really like it's query language but it cannot find a path between two objects like Neo4j which is a killer feature in a CMDB. My dream DB would be a hybrid of Neo4j and Datomic.
An example of where Neo4j really shines is I found a site with BGP route dumps. The file contains over 57 million very redundant Autonomous System paths that are just sequences of a IP prefix and the AS path it is reachable by. By loading each IP prefix and AS hop as
In a sense, Prolog _is_ a database query language. The base facts in Prolog are equivalent to the rows of a table. You can also ‘table’ predicates with variables (over a finite subset of values) by memoizing the results.
>> How can I use Prolog to actually get something done, other than academic tasks?
Choose the task, download Prolog and start coding. That's, generally, how you "get something done".
As to using Prolog as a database query language, I'd say that's like using a piano as a lawn ornament, but you can certainly replace a traditional relational DB with Prolog. The SWI-Prolog website does that and the developers explain how to do it in this article:
And here's some more about using Prolog for good, old-fashioned, web development, in the sense of creating sites that run on the web and have visitors etc etc, particularly the SWI-Prolog website itself:
Consider also checking out Datomic, though technically it's datalog not prolog, and not for connecting to your already-in-use SQL system, but it is a good example of taking the expressive power of logic programming to interface with a database.
I liked the authorization example. I've encountered Prolog articles before, but showing the code alongside an OOP implementation was a nice demonstration of its expressive power.
As a follow-up, I'd love to learn how this auth system could be put into production. In this example, authorization rules are provided in the code (`user_role(mike, supervisor)`) and queried similarly. What if I wanted this system to expose authorization as an HTTP endpoint with REST semantics, and store authorization rules on disk? Would this be straightforward, involved, or impossible? Would I use another language for HTTP, and query a prolog "server" running on the same machine?
> What if I wanted this system to expose authorization as an HTTP endpoint with REST semantics, and store authorization rules on disk? Would this be straightforward, involved, or impossible?
Straightforward. Prolog supports self-modifying code. You can mark the user_role predicate as "dynamic", i.e., modifiable. At runtime you can then read rules from disk or receive them via HTTP or construct them based on some other form of input, and add them to the code, or remove them as needed.
The HTTP part is not standardized; you would need to use libraries specific to some concrete implementation. But the libraries exist.
Indeed. Not using CUDA but Quantum Prolog has parallel maplist and co [1], and the article also contains a short overview and brief comparison with other approaches, including a short discussion of imperative implementations like SWI's (historic?) threading package. Discussion is necessarily limited to that particular workload since parallel Prolog has a long history dating back to the 1990s (the book "Past, Present, Parallel" was an early survey at the time and already contains tens of approaches/academic implementations).
> While SQL isn't normally used as a general purpose programming language I think it's quite illustrative for those otherwise unfamiliar with declarative languages (though apparently it is Turing complete)
SQL itself is not Turing complete in its standard form because it lacks some essential features of a Turing machine, such as the ability to simulate unbounded loops or recursion within a single query.
SQL with procedural extensions, such as PL/SQL (Oracle), T-SQL (Microsoft), and PL/pgSQL (PostgreSQL), are Turing complete because they allow constructs such as loops, conditionals, and recursive functions.
SQL with CTEs is also Turing complete, which is not necessarily ideal. The Rule of Least Power https://en.m.wikipedia.org/wiki/Rule_of_least_power suggests avoiding OP languages. Less powerful languages can be more transparent (great for expressing contracts, e.g. specifications), tractability (proofs, optimization, termination, etc.) and so on. Many systems have been ruined by making them Turing complete.
Others would say datalog elegant and makes it easy to compose statements whereas SQL has an ugly syntax. I mean, ORMs were invented to try to avoid writing SQL but they too have their own problems.
Are there any implementations, of either Prolog or other declarative languages, that try to parallelize parts of their search, then have multiple cores or even a GPU take the problem to speed up solutions?
Am I the only who finds this article to be inaccessible due to color choices and implementation?
I'm really interested in Prolog, but my eyes feel the strain after a few sentences. The reason is that the contrast ratio of some parts is very low, of others excessively high. The constant alternations between these extremes intensifies the effect.
The page looks shredded in Safaris reader mode, so that's no help either.
Hey, I'm the author of the blog. I agree with your criticisms - I originally designed the website for dark mode users and hadn't really revisited the styling afterwards. I'll be doing some tweaking to increase readability.
It's not just you: Its typography and design is quite unsuitable to reading. The lines are too long, there is not enough leading, the typeface is badly chosen, and the black blocks everywhere are unpleasant and off putting.
Hey, I'm the author of the blog. I agree with your criticisms - I originally designed the website for dark mode users and hadn't really revisited the styling afterwards. I'll be doing some tweaking to increase readability.
I have a long standing love affair with Prolog and frustration for its failure to grow. Prolog has poor features for abstraction and is actually not declarative enough!
Prolog's limitations can be great for starting to get the paradigm but then you hit a wall. (Kind of like standard Pascal!)
Mercury and Curry fix some of these limitations as does miniKanren. Integrating CLP is important yet so far always clumsy as standard Prolog provides no way to reify the environment.
Some LP resources:
https://minikanren.org/
https://mercurylang.org/
https://www.curry-lang.org/
https://en.m.wikipedia.org/wiki/Constraint_logic_programming
https://logtalk.org/
Respectfully have to disagree. Prolog has the best features for abstraction of any language I've used, I suspect it may be near an optimal fixed point for metaprogramming expression[3]. I will say the other side of that wall is breathtaking.
Also not sure what you mean, CLP is a first class consideration in many Prologs, esp Scryer Prolog. Check these crazy demos out:
[1] https://youtu.be/h5Xy4YjCZxM
[2] https://youtu.be/5KUdEZTu06o
Just look at this Sudoku solver code (see [2] for explanation):
I have yet to see more elegant code in a general purpose language.[3]: https://github.com/mthom/scryer-prolog/discussions/2347#disc...
Prolog predicates are not first class values. Data structures are not abstract. Compare both with any modern lisp or better with functional languages. Mapping and filtering is awkward. Arithmetic is awkward. Indexing and search strategies are not under programmer control. Modes are awkward. Cut and dynamic assert of global facts are abominations which undermine logical reasoning. Prolog programmers often write metacircular interpreters to fix these problems which is wonderfully easy but kills efficiency. The CLP examples aren't integrated with Prolog's Horn clause resolution model, they're just libraries with strange semantics. I've been an enthusiastic Prolog programmer since the mid 1980s, attended lots of conferences, read lots of papers, etc. There have been many promising attempts to fix these problems but they've only shown up as non-standard features in specific implementations. It's similar to the "curse of Lisp" - everyone does their own thing and no consensus emerges to move the standard forward. But it could be worse if the standard were "feature oriented" rather than eliminating the limitations and flaws by cleanly generalizing the model. I study new logic programming languages avidly hoping to see a worthy successor to Prolog. So far none quite make it. Mercury might do it if it got more love.
> There have been many promising attempts to fix these problems but they've only shown up as non-standard features in specific implementations. It's similar to the "curse of Lisp" - everyone does their own thing and no consensus emerges to move the standard forward.
> But it could be worse if the standard were "feature oriented" rather than eliminating the limitations and flaws by cleanly generalizing the model.
Why do you feel that "eliminating the limitations" is the way forward, and not standardizing common tasks instead, making them ergonomic, uniform, fast?
I don't think that more power can lead to those. Maybe ergonomics and uniformity can happen by accident if a library emerges as the default option for a task, but speed, I don't think it can.
A lot of these comments don't make any sense to me.
> Prolog predicates are not first class values.
Predicates are trivially called, even as variables, with the `call/N` metapredicate.
> Mapping and filtering is awkward
In what sense? The declarative semantics...?
> Arithmetic is awkward
In what sense...? Have you seen clpz?
> The CLP examples aren't integrated with Prolog's Horn clause resolution model
In what sense...? clpz and clpb do this magnificently.
> Indexing and search strategies are not under programmer control.
Most ship with SLG resolution or you can write your own resolution strategy with a simple metainterpreter as an intermediate exercise -- but SLD resolution is already pretty good. In general not needing to think about the indexing and search strategies are a highlight of the declarative semantics of Prolog, its odd to see someone with a "long standing love affair with Prolog" list this as a drawback.
> Modes are awkward.
Modal programming is a defining feature of Prolog. Tell me more about this "long standing love affair", again?
> I've been an enthusiastic Prolog programmer since the mid 1980s
If you are still struggling with mapping, filtering, arithmetic, `call/N`, and CLP in Prolog after nearly 45 years of "enthusiastic" programming, I'd highly recommend checking out Triska's Power of Prolog videos for some guidance, I think you will find them very illuminating.
https://youtube.com/@thepowerofprolog
> Predicates are trivially called, even as variables, with the `call/N` metapredicate.
Yes, that is the definition of "predicates are not first class values". Some things can be called without call/N. Other things can not be called without call/N. These are two separate classes of things. Both of these classes cannot be the first class.
I think there is some confusion around what is "first class" in Prolog. Any syntactically valid construct in (ISO-conforming) Prolog is "first class", including the symbols that are the names of predicates. The fact that Prolog is a homoiconic language makes any valid Prolog code "first class".
"First class" meaning, can be the arguments to a predicate or processed as data.
Predicates (and only predicates) can be called with `call/N` -- although you could write a meta-interpreter with different properties. You could pass in the number `1` and call a randomly determined predicate, as an absurd example.
Perhaps you mean, "the head and body of a predicate are not first class" ? This again is false. They are valid data and can be processed as such -- please see [4] for clarification.
Perhaps you mean "they cannot be looked up dynamically at runtime" -- this is also false, please see [3].
Are there other eligibility requirements for "first class" that we should discuss?
> Any syntactically valid construct in (ISO-conforming) Prolog is "first class"
First class data, yes. First class predicate, no.
> Predicates (and only predicates) can be called with `call/N`
Some class of things that you apparently refuse to call "predicates" can also be called, but without having to use call/N.
> Perhaps you mean, [...]
No. I mean there are first-class callable things and second-class callable things, and second-class things are not first class.
First of all lets be clear: the concepts of "first class" and "callable" are procedural terminology coming from object oriented and functional languages. I am admitting them to the discussion for purposes of comparative language analysis. My criteria is "if a reasonable person would recognize a language construct in Prolog as similar to an equivalent language construct in an OO or FP language, we can discuss it as if it were the same".
However, this is a charitable interpretation that is open to abuse if desired.
It is starting to sound like the criticism is that Prolog is not an object oriented programming language and does not pass contextual object information along with symbols in the same way SICP-style higher order functions are treated in functional programming languages.
This is by design, Prolog is a logic language that describes relationships, not a procedural language.
There is no behavioral difference that distinguishes a Prolog predicate as not "first class". There are many metapredicates designed to accept predicates as arguments, such as maplist/N. This is the primary criteria for supporting first class "callables" (another word poorly suited for Prolog, but I'm admitting it for purposes of conversation) in other languages. I would have assumed that would be a sufficient behavioral affordance.
> there are first-class callable things and second-class callable things
To make this more concrete, please provide some examples of "first-class" and "second-class" "callable things" in Prolog, as well as an example of "first class" and "second class" "callable things" in another language.
Given your level of confidence in your argument, I assume this should be fairly easy to do. Then we might have a concrete basis for discussion.
I really don't care what you "admit". Now you're saying that it doesn't matter whether Prolog has predicates as first-class values, and yet you keep arguing that it does have them. I don't think you're here anymore to establish what statements about Prolog are true or false. You're here for a fight; I'm not here for a fight. Go fight yourself.
Not for you, but purely for the benefit of unfortunate souls who wander by and are confused what there is to argue about:
This predicate calls some other predicate `call_direct/2` in a first-class way. It's a call.It also calls some predicate identified by whatever the variable IndirectCallTarget may be bound to. This is a second-class call. It's frequently referred to as a "meta-call" to signal that it's not a first-class call. It's important to note that the value passed in for the IndirectCallTarget parameter is not a predicate. It cannot be, since there are no predicate values in Prolog. It's the name of a predicate. (Plus maybe a partial argument list; still not a predicate.) Since the thing being meta-called is not a predicate, it must be meta-called specially using the `call/N` builtin. The user has no realistic way of implementing the `call/N` builtin themselves.
> The user has no realistic way of implementing the `call/N` builtin themselves.
Not sure what you mean by realistic, but `call/1` can be implemented by having one simple rule for each existing predicate (now for the sake of the argument ignoring control constructs, which require somewhat more complex processing first) plus a rule for uninstantiated variables and one for an inexistant predicate. And `call/N, N > 1` can now be defined based on it.
Yes, enumerating all predicates in the system and meta-interpreting all control structures seems unrealistic to me. In the sense that no Prolog application developer (as opposed to a Prolog system implementor) would want to do it. Except maybe as an intellectual exercise.
Of course you wouldn't really need to enumerate all predicates in the definition of call/1. You could first run a whole-program abstract interpretation to identify just the ones that can actually be meta-called. Much more appealing :-)
Yes, this technique has been used by several implementations. And any application developer can use `asserta/1` for the very same purpose. Just one rule, that is certainly much more appealing.
I will concede that my tone was not as welcoming or polite as it should be and could rightly be considered combative, so please accept my apologies.
> call_direct_and_indirect(IndirectCallTarget, Input, Result) :- call_direct(Input, Intermediate), % first-class call call(IndirectCallTarget, Intermediate, Result). % second-class call
I see we are at an unfortunate impasse. I assert what you are calling a "second-class call" is usually considered "first-class". I will leave the definition here for readers to decide for themselves. I rest my case and wish you a good day.
https://en.wikipedia.org/wiki/First-class_function
> Higher-order functions: passing functions as arguments
Not specifically aimed at this comment, but it looks like in most Prolog threads here, many commenters seems to plugging in Scryer Prolog, but perhaps, SWI is the most 'batteries included' and mature Prolog implementation for people not familiar with Prolog to try out .
There is a bit of... let's say friction between Markus Triska (Scryer) and Jan Wielemaker (SWI), I seem to remember. The SWI people are much less attached to ISO Prolog (i.e. prone to experiment with non-ISO syntax), and some things that are fixed in the SWI implementation impeded the realization of M. Triska's projects. Generally, people tend to like the new and shiny but there's also a significant philosophical gap between Scryer and SWI.
Now why would syntax be that important? It's because it directly enables homoiconicity, which is central to Prolog metaprogramming features: executing Prolog code returns a Prolog term, that can be read (just like Lisp). This is the distinctive characteristic of Prolog compared to more mainstream solvers, and what makes it 'a good programming language because it's a very dumb theorem prover'.
Wot. SLD Resolution is a "very dumb" theorem prover?
SLD Resolution is sound and refutation-complete and it is the basis not only of Prolog but also the most successful bunch of SAT solving algorithms in the last, dunno, several decades.
"Very dumb theorem prover"!
"Prolog is an efficient programming language because it is a very stupid theorem prover."
-- Richard O'Keefe
So what's that now? An appeal to authority?
SLD-Resolution is sound and refutation-complete (and also complete with subsumption). If you think that O'Keefe is right to say that it's a "very dumb theorem prover" then explain to me why _you_ think so, not who said it.
Because I, too, can quote you authorities- and probably bigger than O'Keefe.
Not an appeal to authority. Just showing that quote wasn't of my invention. I don't really get why you're so riled up. I'm not saying SLD resolution is dumb, just that Prolog stays simple by not including all the clever heuristics and circumstantial techniques of other solvers. Which is a big part of what makes Prolog a nice programming language. It's more a compliment than a critic, really!
I'm not riled up, I even upvoted your OP, but it's uncouth to drop a quote without any context as a reply to a comment. Of course there's going to be misunderstandings.
I didn't remember that quote from O'Keefe. Prolog is indeed not trying to be smart and SLD-Resolution is dead simple - it's a sound and complete deductive inference system with a single rule. The reason Prolog is in turn so simple is because, thanks to the refutation-completeness of SLD-Resolution, you can implement it as a Depth-First Search for resolvents and then spam it until you get a result (or until you hit an infinite branch... oops). That's certainly orders of magnitude more simple than every other solver or automated theorem prover out there, like you say.
If that's what O'Keefe means, that Proolog is not trying to be smart, then OK, but that's not dumb. Every other solver tries to be smart and ends up having to solve an unsolvable problem. Who's dumb now then?
But maybe that's the compliment, I don't remember the context of O'Keefe's comment. Was it in the Craft of Prolog?
TBH, I don't remember where I first read it, but it's all over the web xD. This is all just a misunderstanding: since I knew you were a Prolog expert, I assumed you would recognize my (botched) quote and the context. Yeah, I understand it as: 'better to keep it simple and understandable'
More like a fan than an expert but thanks for the compliment and sorry for yelling at you.
SWI Prolog 7 added "X = Dict.key" syntax and that use of "." makes it fundamentally incompatible, ISO standard breaking, backwards incompatible to previous Prologs, sideways incompatible to other Prologs.
This is a worse sin in Prolog than it seems at a glance, because one of the strengths Prolog has is code-is-data / data-is-code metaprogramming. That includes exporting code as Prolog terms (use cases you might use CSV or JSON for in other languages), reading them back in as Prolog data (perhaps in a different Prolog system or different version) and executing the data as Prolog code. With that "." syntax change no other Prolog system can guarantee to read all SWI Prolog code, SWI 7 can't guarantee to read all SWI 6 code, and SWI 6 can't guarantee to read all SWI 7 code.
Code might say "connect_to_mongodb()" and you don't have mongodb in your system so you cannot run it, but you can read the code in as data and it will parse, just like reading in JSON which has a string mentioning some library you don't have; you can still introspect it and write reports like "what names does this data reference?", you can transform it and export it, or pass it through untouched. With SWI's new dot syntax the code might not parse at all, like an incompatible proprietary JSON syntax where you can't even import it. Code written 30 years ago which uses the dot in the old standard way might trigger SWI to try and read it in the Dict.key way and fail. Code exported from SWI 7 might include this syntax which other systems can't import.
I don't know how often it will come up in practise, but it seems that SWI could have done it with a slightly different syntax that would have been as convenient to use and also been a standard term and wouldn't have made this split at all. SWI has some other differences versus ISO Prolog, things inside error handling, for example, but none quite so fundamental as this. And it's annoying from the outside because you can wade into a big-ball-of-mud design-by-committee language, but if you want to look at an esoteric language and they're all arguing over who is most pure and virtuous you have to pick a religion before you can write Hello world.
Markus Triska's Power of Prolog series has been some of the best Prolog publicising material in years, something that isn't (totally) a dry academic text of "a --> a | a. a(A) :- a([a|As]) , a(As).", it must be a huge amount of work on his part. He uses and contributes to Scryer Prolog, and he is especially interested in Constraint Language Programming which he wrote/maintained in SWI[1], and has moved the newer versions to Scryer.
That said, I strongly agree with your comment, SWI is batteries included, it has lots of builtins, a packaging system to download and install modules, it has a debugger and graphical debugger and tracer and just a ton of decades of development and polish that Scryer hasn't had time to develop yet, and is much much friendlier for people not familiar with Prolog to try out. You have to be pretty hardcore to be writing Scryer Prolog in EMACS buffers with no predicate search, no help, limited libraries, limited documentation, limited debugging, very small online community even by Prolog standards which is already small.
When you could open https://swish.swi-prolog.org/ and click 'new Program' and as a beginner be able to write syntax highlighted code in browser with no download, no setup, no install, no account registration, but it's SWI Prolog.
Query "apropos(string)" in the query box in the lower right and see things like "string_lower/2" and "string_concat/3". That search is convenient and those predicates are SWI custom ones.
Query "help(format)" and see HTML styled, coloured, scrollable help for the text formatting domain specific language. That's enormously useful.
[1] https://www.swi-prolog.org/pldoc/man?section=clpfd "Author: Markus Triska"
The Power of Prolog series is great and what Markus is doing is vital: We must teach that Computer Science is not an exotic, marginal way of approaching software development, but the foundation that we constantly draw upon and inhabit.
Find the lectures here: https://www.youtube.com/@ThePowerOfProlog
> SWI 7 can't guarantee to read all SWI 6 code
> Code written 30 years ago which uses the dot in the old standard way might trigger SWI to try and read it in the Dict.key way and fail.
Why would they do that? SWI 7 reading SWI 6 or ISO prolog code should be rather trivial, shouldn't it?
I don't know if they could do a try/fallback or if one is available as a setting (I haven't looked), but apparently they don't by default; Scryer Prolog:
SWI Prolog 9:> [...] might [...] might [...] might [...] might [...] might [...]
All of what you say is true, and yet practical applications that did break are somehow not talked about quite as much as hypothetical applications that might have broken. SWI could reuse infix dot precisely because it was universally considered bad style to use it in the old style, and hence was not used in the old style.
Which is not to say that I think the record syntax is particularly useful. But I wish not every Prolog discussion devolved into "Markus Triska fanpersons regurgitate walls of text about infix dot".
I wish not every Prolog discussion had a top comment about Mercury, Curry, Minikanren, et al; but I think you missed the end of my comment where I recommended SWI over Scryer for most people; I am unashamedly a Markus Triska fanperson but that doesn't mean I do everything he does, or that I subscribe to ISO Purity over all else. It was more that the parent comment claimed a "friction between two people" and I think that's unfair and leaves readers expecting soap opera drama where someone insulted someone's mother; whereas it is a difference of opinion about language compatibility and standards - and once you know that you can decide whether it matters to you and your potential use cases (which, again, it doesn't to me and I think it doesn't to anyone who hasn't touched Prolog before).
I am not aware of any practical applications which have broken, but then I'm not aware of anyone using Prolog for anything, anywhere.
A practical example: Void Linux installer implemented in GNU Prolog (https://github.com/sdbtools/void-pi).
> I wish not every Prolog discussion had a top comment about Mercury, Curry, Minikanren, et al
Absolutely. Datalog too.
> but I think you missed the end of my comment where I recommended SWI over Scryer for most people
I did not miss that. I have no complaints about that part of your comment. I complained about the prologue to it, which I thought was beside the point and devalued the whole thing.
> but then I'm not aware of anyone using Prolog for anything, anywhere.
Fortunately, other Triska fans have got you covered with the standard talking points: https://news.ycombinator.com/item?id=42829782 ;-)
>> Code might say "connect_to_mongodb()" and you don't have mongodb in your system so you cannot run it, but you can read the code in as data and it will parse, just like reading in JSON which has a string mentioning some library you don't have; you can still introspect it and write reports like "what names does this data reference?", you can transform it and export it, or pass it through untouched. With SWI's new dot syntax the code might not parse at all, like an incompatible proprietary JSON syntax where you can't even import it. Code written 30 years ago which uses the dot in the old standard way might trigger SWI to try and read it in the Dict.key way and fail. Code exported from SWI 7 might include this syntax which other systems can't import.
So just write a translation layer, or add some flags to your Prolog so it can parse SWI's syntax. SWI does that (it has flags to adjust itself to other Prologs' syntax). Do other Prologs do that? Not to my knowledge, but why not? It's no big deal and certainly not a big enough deal to cleave a rift in the Prolog community, as if it wasn't small enough and dwindling already. I think some people have convinced themselves it's "better to be first in the village than second in the city" and they just don't want to work with others.
And as it sounds like you probably know, SWI is by far not the only Prolog to commit that cardinal sin of breaking portability. Basically every Prolog ever does that. Every single one. The ISO standard is just as opinionated as everybody else about what Prolog should be like (and btw ISO is not Edinburgh, let's not forget- and who came first, huh?) except it has delusions of grandeur because ISO.
I will take batteries included over nose-in-the-air "we have strict adherence to standards" any day.
> "cardinal sin of breaking portability. Basically every Prolog ever does that. Every single one."
Indeed; still Markus Triska speaks positively about, and recommends, different Prolog systems. He seems to prioritise things above ISO purity, and is not king of the hill of Scryer Prolog[1], he doesn't comment like others who act as if "the village and city can burn to the ground for all I care, heresy against ISO Prolog is NEVER acceptable". So when he's finding this objectionable even after considering that, it seems reasonable for me to weight it more strongly. It's not enough to make me stop using SWI, or stop me recommending it (as I did above).
[1] for other readers, Mark Thom's Prolog-in-Rust to be a type inference engine for his Lisp-in-Rust: https://github.com/mthom/scryer-shen
The lack of portability is a bad problem in the Prolog world and it has bit me a few times, but surely the solution is for all the implementers to work together, rather than engage in petty feuding.
But the biggest problem of the Prolog community is what I pointed out above: there's very few of us and the field isn't really growing much.
:(
Mark Thom's intention is implementing Shen. I guess it could count as a lisp and that's what you meant, but as lisps go, Shen is highly atypical.
My little pet peeve with prolog is the lack of context parameters (which can be thought as a type of abstraction).
For example, imagine I'm writing a maze solver. The maze solver predicate receives obviously, but it has to pass as a parameter the maze again and again to all sub-predicates. There is no concept of "current maze", like in OO you would have with this.maze, or in Haskell you would do with a reader monad. As a result, all the "internal" predicates in a module get full of parameters all they do is pass around until some final predicate uses it to do some calculation.
Either that or you do the assert/retract dance and now you have bigger problems.
Quantum Prolog has this feature where you can query against a dynamic database, not just the global default database; ie. where in regular Prolog (and in Quantum Prolog as well of course since it's full ISO) you query
you can instead query introducing a clause-list as first parameter to "?-".In the description [1], this is used to avoid destructive database manipulation via assertz/retract builtins, and thus to allow much more complex combinatorial planning problems and action post-conditions to be solved/optimized without resorting to ad-hoc hacks. But you can also use this for mere convenience in large knowledge graphs, and a technique very similar to it, albeit implemented in Prolog itself and not provided with native speed, has been used as a historic extension to Prolog DCG parsing (cf. definite-clause translation grammars by Dahl et al).
[1]: https://quantumprolog.sgml.net/container-planning-demo/part2...
There are multiple ways to accomplish this, but the one that is the most straightforward is to simply make an object mapping of the type you are familiar with via AVL trees[1]. Easy way to get the "this.maze" semantics. You can get global context and local context via "blackboard"[2] semantics.
However quite frankly the most powerful way to do this is not obvious because it doesn't translate well to other languages: meta-interpreters[3].
[1]: https://www.scryer.pl/assoc
[2]: https://www.scryer.pl/iso_ext.html#bb_get/2
[3]: https://youtu.be/nmBkU-l1zyc
Could you elaborate on all of these?
For [1], you would either need to pass the AVL tree around or to have it as a global (which is not wanted), and instead pass the key (the "this" context which is different for different mazes) for the context around.
For [2] again you have a global table (with copying semantics as for assert/retract? or maybe without copying? the docs don't say). But again you would need to pass a key around.
[3] is... yeah. I mean, sure, you could demonstrate this with a toy metainterpreter on a toy example. But do you really want to run your whole application inside a metainterpreter?
One could also abuse DCG syntax, with the context being some state object instead of a DCG list.
A more practical way would be Logtalk-like code generation. The most practical way would be actual Logtalk. Unfortunately, last I heard Scryer refused to host Logtalk for no real reason.
> Could you elaborate on all of these?
Certainly.
> For [1], you would either need to pass the AVL tree around or to have it as a global (which is not wanted), and instead pass the key (the "this" context which is different for different mazes) for the context around.
Not sure how tracking references is different here than any other programming language. Passing objects around is pretty common in OO programming. An AVL tree is just the underlying abstraction used to implement the object. You don't have to implicitly supply the "this" parameter to each "object" predicate if you don't want to -- you could insert that yourself via compilation (with term/goal expansion)[4] or interpretation (via meta-interpreters) if you were really interested in that level of syntactic sugar.
> For [2] again you have a global table (with copying semantics as for assert/retract? or maybe without copying? the docs don't say). But again you would need to pass a key around.
You could use global or local semantics as desirable. The blackboard has a global version that is persistent across application state or a local version that provides lexical context which unwinds on backtracking. Not sure how "passing a key around" is different than most other forms of programming, but if you wanted to compile it away, please review the techniques listed above.
> [3] is... yeah. I mean, sure, you could demonstrate this with a toy metainterpreter on a toy example. But do you really want to run your whole application inside a metainterpreter?
A "toy" meta-interpreter? Meta-interpreters are as fundamental to Prolog as for-loops are to Python. Certain applications, such as games, are run "entirely inside a loop", so I'm not sure how this criticism applies. You can run as much or as little of your application inside a meta-interpreter as you want. The value proposition of Prolog is that the simple homoiconic syntax allows for powerful meta-interpretation. I'd suggest checking out the video I linked to in [3] if you have doubts on that topic.
> One could also abuse DCG syntax, with the context being some state object instead of a DCG list.
State transitions (a sequence of states) are a great use for DCG syntax! I wouldn't call that "abuse".
> A more practical way would be Logtalk-like code generation. The most practical way would be actual Logtalk.
If you are willing to give up the most powerful features of Prolog, sure.
> Unfortunately, last I heard Scryer refused to host Logtalk for no real reason.
Hmm, I wonder if that's the real story :)
[4]: Please see Section 3 of my talk if you are interested in a more thorough explanation of goal/term expansion. https://docs.google.com/presentation/d/e/2PACX-1vR4Q0Ohs66mj...
> You don't have to implicitly supply the "this" parameter to each "object" predicate if you don't want to [...] if you were really interested in that level of syntactic sugar.
Given that the original "feature request" (https://news.ycombinator.com/item?id=42829985) was this:
>>>> There is no concept of "current maze", like in OO you would have with this.maze, or in Haskell you would do with a reader monad. As a result, all the "internal" predicates in a module get full of parameters all they do is pass around until some final predicate uses it to do some calculation.
I would say that yes, the OP wanted exactly that level of syntactic sugar and your previous suggestions [1] and [2] were addressing something else entirely.
> you could insert that yourself via compilation (with term/goal expansion)[4]
Yes, that's why I meant above by "Logtalk-like code generation". Suggesting that I study the thing that I suggested feels a little condescending.
Yes, the OP is probably unaware of the recent advancements in Prolog. There is a set of techniques using pure Prolog that have made the language incredibly powerful compared to the techniques of the 80s and 80s. The more we use the abstract features of Prolog, the more powerful it becomes.
The declarative expression of the problem is elegant but even if this toy example is successfully resolved, make it a little more complicated and you'll have the interpreter ping-pong between two states infinitely.
As I see it. Prolog as a language and idea is great but the existing solvers are useless for any real problem ... or you'll have to resort to cuts and memorizing states and at least partially implement an imperative solution that you yourself have to come up with. And that's totally killing the magic.
Well, I mean... Prolog is an implementation of 1st order logic with syntax sugar. So basically, Prolog is incredible if your problem can be expressed within the framework, but less so if it can't. That's pretty much why there were extension attempts such as lambda Prolog.
you're simplifying the practicalities of prolog. there are many problems that you can express declaratively to the t. and yet many (all?) solvers aren't able to reduce it to a solution. the search isn't even successfully brute forcing - it will get stuck in some branch and switch endlessly between its leafs. and then it's up to you to figure that out and help the solver. even then prolog has its value but it fails at delivering the primary promise: you describe the problem, it finds a solution.
That's the oldest complaint in the book about Prolog: "it's not 100% declarative". OK. So use Java. Or C. You think you'll have more declarative fun writing a Zebra Puzzle solver in C, than in Prolog? Be my guest.
No, the truth is that Prolog is a unique language that is almost perfectly poised between the two extremes of beautiful but unusable formal purity and everyday programming utility. Prolog makes pragmatic choices when it has to and chooses to sacrifice declarative purity for the sake of performance and usability, because that's the only thing that makes sense considering that we have to run our programs on real computers, programmed by real programmers.
And then people complain that it's no good because you can't write a solver in a purely declarative form, even though you can't even get close to the declarative features of Prolog in most other languages; except ASP, which is so declaratively pure that it doesn't even have lists.
That's just a very poor criticism, poorly thought out and really meaningless in practice.
my criticism cuts to the chase. that's why you write such a lengthy rebuttal. cause it hurts your feelings.
> So use Java. Or C. You think you'll have more declarative fun writing a Zebra Puzzle solver in C, than in Prolog?
and that, my dear friendo, is _whataboutism_!
I'd say Prolog delivers in a (relatively wide) subset of its domain of application. For instance, I'm writing a solver for some common issues in epidemiology, at the moment. I was able to write a fully declarative (and purely relational) solution! But yes, some applications are better suited than others.
Look also to sudoku solvers in Z3: [0] also papers such as "Evaluating SAT and SMT Solvers on Large-Scale Sudoku Puzzles" [1].
[0] https://github.com/grencez/grencez.dev/blob/trunk/2015/z3-so... [1] https://arxiv.org/pdf/2501.08569
The thing with Prolog is that it’s beautiful for solving very specific and well-defined combinatoric problems. Steer away and you hit a wall.
And I have yet to understand this.
Well, that's why language paradigms are a thing - if you are not familiar with any language in the logic paradigm but are an expert in the OO-paradigm, this could take a little bit to wrap your head around. Triska is an excellent teacher of Prolog, be sure to check out his videos linked.
I am assuming it is a close relative to Norvigs solver https://norvig.com/sudoku.html
Maybe watch the second link I posted?
You have "Rows" repeated eight times in this short snippet. You have all the rest of your variables as two letter names. It feels low level, almost like Fortran.
Speaking of Fortran: please paste the equivalent JavaScript
> Prolog has poor features for abstraction
That's actually what this article presents as its strength and simplicity. The straightforward choice in Prolog is to use global "who may do what" tables. In contrast, the author overengineers a Kotlin solution and then says "look, this is overengineered". I think global tables would make the Kotlin code half as long and much simpler too.
> Mercury and Curry fix some of these limitations
At the cost of introducing new ones. Mercury makes it effectively impossible to pass around partially instantiated structures.
I take it you have some gripe with https://www.scryer.pl/clpz? Could you explain in more detail?
How does MiniKanren fix some limitations? MiniKanren corresponds to the purely relational subset of Prolog.
By allowing you to use the features of the host language to complement the features of miniKanren. Having good support for multiple programming paradigms is better than trying to make one paradigm fit all needs. Poplog[1] was an earlier attempt to provide such synergies but it failed to gain market share. It's now free software so take a look! The Racket ecosystem is another approach where each module can choose a language with some of them being Prolog-like[2]. [1] https://en.m.wikipedia.org/wiki/Poplog [2] https://racket-lang.org/languages.html
Ok, but MiniKanren isn't intrinsic to Scheme. I agree Racket makes it especially easy to embed sub languages, but you could embed core relational Prolog just as well as MiniKanren. My understanding of your statement is that Scheme and MiniKanren share sexp syntax, but the same applies: you could embed an sexp-based Prolog just as well. The only remaining MiniKanren advantage is then to have a complete search strategy, this I concede.
I didn't connect miniKanren to Scheme. I said "Host Language." I did suggest the value of a multi-paradigm host language.
Not forgetting Picat! https://www.hakank.org/picat/
Doesn’t Mercury declare each form of a rule independently?
Very thankful for listing here.
I think Picat also falls in this category.
Also Racket and Julia have a Prolog implementation.
In a long forgotten past a large part of my graduation was Prolog (I was as far ahead then as i'm behind now with the ol' AI thing; I worked on mixing neural nets, reasoning with uncertainty with Prolog at the time) and, after hallucinatory episodes living, sleeping, (day)dreaming in Prolog for months on end, when something was finished I was always so surprised how clean, readable and 'too little' the code looked for what it did. Once you really grok it, it's a magic tool. I replaced it with Common Lisp after (in my uni, there was no mention of Lisp; we didn't even know it existed basically besides some weird scribbles in papers which were easy enough to study so we didn't give it more thought) and have the same feelings/experiences there but CL is usable for basically anything, including logic programming.
I really wish there was "regex for prolog", ie: when pounding away in JavaScript be able to do:
...like writing a whole web app in prolog sounds terrifying (same as writing a whole web app in regex), but recognizing and having some excellent interop between "modes" is obviously useful for regex, sometimes sql is supported in other languages, but even with the usefulness of prolog outcomes, there's almost never been that convenient "this section is logic" in the same way that we've universally adopted "regex" for string matching.It may "sound terrifying" but it's likely to be much more pleasant than you think:
https://github.com/Anniepoo/swiplwebtut/blob/master/web.adoc
You might want http://tau-prolog.org/documentation#js
It's been a while since I used it, but look at the miniKanren implementations for your favorite programming language (js in your case, but there are a lot). It's basically a stripped-down version of logic programming.
I started learning prolog just a few months ago, when I stumbled upon https://linusakesson.net/dialog/ which is a spin on prolog optimized for writing interactive fiction.
As a sweet and short tutorial I can recommend these slides: https://www.cs.toronto.edu/~hojjat/384w10/
If you want to dive into how Prolog works under the hood I can recommend https://github.com/a-yiorgos/wambook
I terms of Prolog implementations I played a bit with https://www.scryer.pl but it still feels rough around the edges.
SWI-Prolog is the most popular and most batteries included Prolog: https://www.swi-prolog.org With its libraries and documentation it is a very practical language. What surprised me is, that you can easily produce amazingly small stand-alone binaries.
I read about dialog in another HN thread a few weeks ago. Between then and now I've had the itch to write some interactive fiction, but I could not for the life of me remember the name of that project.
Thanks!
I assume you're already au fait with Inform* family of languages...
> The reverse predicate from this section should not be used in practice - most Prolog implementations actually provide a built-in version which is a lot more performant than our implementation.
That feels like cheating. If you shouldn't use the implementation shown, then why do you even show it? Let us see the performant version!
That's like Haskell's quickSort implementation in a couple of lines... beautiful but horrendously non-performant as it doesn't actually implement the algorithm, it just implements the "idea" (while losing all the performance of the actual algorithm, which requires in-place mutation).
No built-in is needed for an efficient reverse. It's just one or two lines longer because you need to write a tail-recursive helper with an accumulator, same as in functional languages: https://stackoverflow.com/a/74777180
I always enjoy reading positive pieces about Prolog but without touching on the implications of the principles on display, this article may do more harm than good.
You would ask reasonable questions like, "for God's sake, why?". It feels like you wouldn't use Prolog for anything besides an intellectual game.
Regarding the why:
Some of those reasons include Definite Clause Grammars, Meta-Interpreters, 1st class constraint logic programming, reified conditionals, and term/goal expansion.
There are a lot of exciting modern advances with Prolog, especially Scryer Prolog.
Check out Power of Prolog and get your mind blown: https://youtube.com/@thepowerofprolog
one example that changed my view of prolog was http://faculty.cooper.edu/smyth/cs225/ch7/prolog.htm (a toy compiler in prolog)
And this is nothing new. People already knew how to write compilers in Prolog (easily) in the 90s. The problem with Prolog is that it requires a change in the way you think about problems, to a more declarative way. Programmers are in general not willing to do this since the result will be not as performant as what they can do with C. There must be a revolution in programming education and tools before people fully understand how Prolog works.
"since the result will be not as performant as what they can do with C" -- This isn't the main reason, but it's also not really true. Paradigm changes don't imply "less performance". To the extent programmers believe, herd-like, "C is fast therefore my program will be fast", they are almost always wrong.
A lot of programmers resist learning anything new, for various reasons, but most charitably because they are never exposed to new ideas or paradigms.
yeah yeah i got that too after a while, which is also why i like non mainstream programming languages, after a while you're tired writing more versions of the same routines/procedures/methods that won't help you find better solutions
Something doesn't have to be new to be valuable (XKCD "Ten Thousand" et al). A revolution starts with inspiration.
How can I use Prolog to actually get something done, other than academic tasks?
Say I want to use it as a database query language, presumably that's not going to happen, right?
> Datalog is a declarative logic programming language. While it is syntactically a subset of Prolog, Datalog generally uses a bottom-up rather than top-down evaluation model. This difference yields significantly different behavior and properties from Prolog. It is often used as a query language for deductive databases.
https://en.m.wikipedia.org/wiki/Datalog
do you know what you are writing about? I mean have you actually done something with datalog? and then _which_ datalog? if yes, then you are probably someone working with it academically or the answer is no. because try to even set a toy project up with it (for the purpose of learning how to use it) and you'll quickly run into unmaintained interpreters, discussions of what datalog is and what not and you can choose between difficult to understand academic papers or simplistic introductions that lead you no where.
I have found two somewhat usable (your point still stands): soufflé (high performance but more limited) and DES, which works well for some simple personal data management, after some code massage (it’s written in Prolog). Any other recommendations? And since the prolog experts are here: what do you think about Ciao? Seems quite polished but also adventurous to (non-expert) me
Have you tried Datomic?
no.
https://github.com/Datomic/codeq : last update to that repo was 12 years ago.
it's JDK which I find unappealing.
also, how close is it to Datalog?
https://github.com/gns24/pydatomic : last update 11 years ago.
and that's representative of pretty much anything regarding Datalog.
So, I'll just stick to Prolog then.
---
have you?
would you recommend it?
Ok just to clarify, Datomic is a Clojure thing. It is free to use but closed source. It is an excellent database that is used, owned, and financed by Nubank, the largest and most rapidly growing bank in Brazil.
It is not Datalog syntax but heavily inspired by Datalog.
I'm throwing this in here just for clarification, I don't want to see Datomic as collateral damage in this conversation.
There is Datascript. I am not a Clojure guy, so it is not clear to me if it pulls datomic as a dependency.
Datascript is very similar to Datomic, except that it runs in ClojureScript and is an in-memory datastore with no concept of history or point-in-time queries. The schemas are also much looser than Datomic.
Otherwise, many syntax and semantics are similar.
No dependency on Datomic as Datomic is Java and DataScript is JavaScript.
Ah thank you.
I tried using Datomic Pro for a CMDB. I liked how logical queries were but I ended up going with Neo4j instead because finding paths between two nodes is incredibly useful in IT.
https://central.sonatype.com/artifact/com.datomic/local/1.0....
mhm ... sounds like you don't know what you are talking about if you conflate Neo4j/Cypher with Datalog ... because "in IT".
I'm fully aware they are very different things. I'm just saying I have tried using datomic and I really like it's query language but it cannot find a path between two objects like Neo4j which is a killer feature in a CMDB. My dream DB would be a hybrid of Neo4j and Datomic.
An example of where Neo4j really shines is I found a site with BGP route dumps. The file contains over 57 million very redundant Autonomous System paths that are just sequences of a IP prefix and the AS path it is reachable by. By loading each IP prefix and AS hop as
(Prefix)-[:ANNOUNCED_BY]->[:AS]-[:BGP_NEXT_HOP]->[:AS]
I can easily trace paths from one prefix to another by going
MATCH path = (p1:Prefix)-[:*]->(p2:Prefix) return path
which will return which AS announce the prefixes and all BGP paths between them. It really is very powerful.
No, unless you count cancer research[1], particle physics experiments[2], and government funding allocations[3].
[1]: https://dcnorris.github.io/precautionary/index.html
[2]: https://github.com/mthom/scryer-prolog/discussions/2441
[3]: https://link.springer.com/chapter/10.1007/978-981-97-2300-3_...
Regarding how, check out Power of Prolog on YouTube.
+ https://sicstus.sics.se/customers.html
In a sense, Prolog _is_ a database query language. The base facts in Prolog are equivalent to the rows of a table. You can also ‘table’ predicates with variables (over a finite subset of values) by memoizing the results.
>> How can I use Prolog to actually get something done, other than academic tasks?
Choose the task, download Prolog and start coding. That's, generally, how you "get something done".
As to using Prolog as a database query language, I'd say that's like using a piano as a lawn ornament, but you can certainly replace a traditional relational DB with Prolog. The SWI-Prolog website does that and the developers explain how to do it in this article:
Can I replace a LAMP stack with SWI-Prolog?
https://www.swi-prolog.org/FAQ/PrologLAMP.md
And here's some more about using Prolog for good, old-fashioned, web development, in the sense of creating sites that run on the web and have visitors etc etc, particularly the SWI-Prolog website itself:
Eat Your Own Dog Food
https://www.swi-prolog.org/dogfood.html
There you go: https://github.com/aarroyoc/postgresql-prolog
Consider also checking out Datomic, though technically it's datalog not prolog, and not for connecting to your already-in-use SQL system, but it is a good example of taking the expressive power of logic programming to interface with a database.
EDIT: (too late to edit above)
s/logic programming/relational programming/
it isn't as expressive as LP or CLP and works best embedded in a functional-biased language
For example: Void Linux installer implemented in GNU Prolog (https://github.com/sdbtools/void-pi).
Ditto!
I liked the authorization example. I've encountered Prolog articles before, but showing the code alongside an OOP implementation was a nice demonstration of its expressive power.
As a follow-up, I'd love to learn how this auth system could be put into production. In this example, authorization rules are provided in the code (`user_role(mike, supervisor)`) and queried similarly. What if I wanted this system to expose authorization as an HTTP endpoint with REST semantics, and store authorization rules on disk? Would this be straightforward, involved, or impossible? Would I use another language for HTTP, and query a prolog "server" running on the same machine?
> What if I wanted this system to expose authorization as an HTTP endpoint with REST semantics, and store authorization rules on disk? Would this be straightforward, involved, or impossible?
Straightforward. Prolog supports self-modifying code. You can mark the user_role predicate as "dynamic", i.e., modifiable. At runtime you can then read rules from disk or receive them via HTTP or construct them based on some other form of input, and add them to the code, or remove them as needed.
The HTTP part is not standardized; you would need to use libraries specific to some concrete implementation. But the libraries exist.
https://github.com/Anniepoo/swiplwebtut/blob/master/web.adoc
FYI, composer 2 (the official PHP package manager) uses prolog to figure out if a package can be installed or not.
When it’s not possible, you get a detailed explanation why it’s not possible
It uses a SAT solver, not Prolog. https://news.ycombinator.com/item?id=17686801
I think Lambda Prolog, is the only language that physically hurt my brain... in a good way.
But damn, it felt like an extreme muscle stretching exercise. Painful when doing it, but you feel SO good after :)
Having used Trino/Athena and BigQuery extensively, I am curious about the state of parallelism in the available prolog implementations.
Being able to push the calculations to CUDA or the google/AWS "cluster" feels like it could be the game changer for a system like this.
The declarative nature of the language should leave any imperative implementation far behind when it comes to complex calculations.
Indeed. Not using CUDA but Quantum Prolog has parallel maplist and co [1], and the article also contains a short overview and brief comparison with other approaches, including a short discussion of imperative implementations like SWI's (historic?) threading package. Discussion is necessarily limited to that particular workload since parallel Prolog has a long history dating back to the 1990s (the book "Past, Present, Parallel" was an early survey at the time and already contains tens of approaches/academic implementations).
[1]: https://quantumprolog.sgml.net/bioinformatics-demo/part2.htm...
Fun fact: A large portion of TerminusDB's codebase is written in Prolog. https://github.com/terminusdb
> While SQL isn't normally used as a general purpose programming language I think it's quite illustrative for those otherwise unfamiliar with declarative languages (though apparently it is Turing complete)
SQL itself is not Turing complete in its standard form because it lacks some essential features of a Turing machine, such as the ability to simulate unbounded loops or recursion within a single query.
SQL with procedural extensions, such as PL/SQL (Oracle), T-SQL (Microsoft), and PL/pgSQL (PostgreSQL), are Turing complete because they allow constructs such as loops, conditionals, and recursive functions.
SQL with CTEs is also Turing complete, which is not necessarily ideal. The Rule of Least Power https://en.m.wikipedia.org/wiki/Rule_of_least_power suggests avoiding OP languages. Less powerful languages can be more transparent (great for expressing contracts, e.g. specifications), tractability (proofs, optimization, termination, etc.) and so on. Many systems have been ruined by making them Turing complete.
I'd upvote this twice if I could.
It is a great strength of the popular subset of SQL that it is _not_ Turing complete.
Ansi SQL 99 defines recursive ctes.
https://en.m.wikipedia.org/wiki/SQL:1999
Using SQL is perfectly fine.
Datalog on the other hand is absurdly hard to work with.
To each their own.
Others would say datalog elegant and makes it easy to compose statements whereas SQL has an ugly syntax. I mean, ORMs were invented to try to avoid writing SQL but they too have their own problems.
> SQL has an ugly syntax
Speak for yourself. I’ve always found it to be very clear and concise.
Are there any implementations, of either Prolog or other declarative languages, that try to parallelize parts of their search, then have multiple cores or even a GPU take the problem to speed up solutions?
It's actually quite pleasing to see much health debate in these comments. Shows life in this amazingly powerful language.
Am I the only who finds this article to be inaccessible due to color choices and implementation?
I'm really interested in Prolog, but my eyes feel the strain after a few sentences. The reason is that the contrast ratio of some parts is very low, of others excessively high. The constant alternations between these extremes intensifies the effect.
The page looks shredded in Safaris reader mode, so that's no help either.
Hey, I'm the author of the blog. I agree with your criticisms - I originally designed the website for dark mode users and hadn't really revisited the styling afterwards. I'll be doing some tweaking to increase readability.
It's not just you: Its typography and design is quite unsuitable to reading. The lines are too long, there is not enough leading, the typeface is badly chosen, and the black blocks everywhere are unpleasant and off putting.
Hey, I'm the author of the blog. I agree with your criticisms - I originally designed the website for dark mode users and hadn't really revisited the styling afterwards. I'll be doing some tweaking to increase readability.
Love the links to SWISH playground: really got me to want to try it out!
Other playground (wasm based): https://ciao-lang.org/playground
[dead]
[dead]