The Simplicity of Prolog
bitsandtheorems.com
bitsandtheorems.com
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://en.m.wikipedia.org/wiki/Constraint_logic_programming
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.
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):
sudoku(Rows) :-
length(Rows, 9),
maplist(same_length(Rows), Rows),
append(Rows, Vs), Vs ins 1..9,
maplist(all_distinct, Rows),
transpose(Rows, Columns),
maplist(all_distinct, Columns),
Rows = [As,Bs,Cs,Ds,Es,Fs,Gs,Hs,Is],
blocks(As, Bs, Cs),
blocks(Ds, Es, Fs),
blocks(Gs, Hs, Is).
blocks([], [], []).
blocks([N1,N2,N3|Ns1], [N4,N5,N6|Ns2], [N7,N8,N9|Ns3]) :-
all_distinct([N1,N2,N3,N4,N5,N6,N7,N8,N9]),
blocks(Ns1, Ns2, Ns3).
I have yet to see more elegant code in a general purpose language.[3]: https://github.com/mthom/scryer-prolog/discussions/2347#disc...
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.
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
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.
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...
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.
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).
[1]: https://quantumprolog.sgml.net/container-planning-demo/part2...
[0] https://github.com/grencez/grencez.dev/blob/trunk/2015/z3-so... [1] https://arxiv.org/pdf/2501.08569
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'.
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"!
-- Richard O'Keefe
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.
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?
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"
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.
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
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.
:(
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 am not aware of any practical applications which have broken, but then I'm not aware of anyone using Prolog for anything, anywhere.
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 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?
?- X = '.'(1,'.'(2,'.'(3,[]))).
X = [1,2,3].
SWI Prolog 9: ?- X = '.'(1,'.'(2,'.'(3,[]))).
ERROR: Type error: `dict' expected, found `3' (an integer)Find the lectures here: https://www.youtube.com/@ThePowerOfProlog
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.
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.
> 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_!
> 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.
> 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.
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.
"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 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.
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.
Not for you, but purely for the benefit of unfortunate souls who wander by and are confused what there is to argue about:
call_direct_and_indirect(IndirectCallTarget, Input, Result) :-
call_direct(Input, Intermediate), % first-class call
call(IndirectCallTarget, Intermediate, Result). % second-class call
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.
> 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
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 xsNot 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.
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 :-)
I think Picat also falls in this category.
Also Racket and Julia have a Prolog implementation.
let options = { foo: 1, bar: 2, ... }
```prolog
$X :- fromJson( options )
Solution = Optimize( $X )
...
```
...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.https://github.com/Anniepoo/swiplwebtut/blob/master/web.adoc
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.
Thanks!
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).
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
A lot of programmers resist learning anything new, for various reasons, but most charitably because they are never exposed to new ideas or paradigms.
Say I want to use it as a database query language, presumably that's not going to happen, right?
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?
https://central.sonatype.com/artifact/com.datomic/local/1.0....
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.
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.
Otherwise, many syntax and semantics are similar.
No dependency on Datomic as Datomic is Java and DataScript is JavaScript.
[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.
s/logic programming/relational programming/
it isn't as expressive as LP or CLP and works best embedded in a functional-biased language
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
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?
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.
When it’s not possible, you get a detailed explanation why it’s not possible
But damn, it felt like an extreme muscle stretching exercise. Painful when doing it, but you feel SO good after :)
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.
[1]: https://quantumprolog.sgml.net/bioinformatics-demo/part2.htm...
> 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.
I think it can be read as: If you care about speed do not use Prolog, instead write a "built-in" solution.
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.
It is a great strength of the popular subset of SQL that it is _not_ Turing complete.
Datalog on the other hand is absurdly hard to work with.
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.
Speak for yourself. I’ve always found it to be very clear and concise.
SELECT <tuples> FROM <table> [[type of] JOIN other_table ON ?, …] [WHERE ? [boolean operator], …] [ORDER BY ? [DESC]] [LIMIT ?]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.