4 ms·
> If anyone has success integrating Prolog in modern software please share, I'm really curious. Not sure if these count but: - Gerrit's submit predicates are
by bjackman 3y ago
> If anyone has success integrating Prolog in modern software please share, I'm really curious.
Not sure if these count but:
- Gerrit's submit predicates are configured in Prolog. (Edit: deprecated!)
- An internal product I worked with at Google is built around a Datalog knowledge base that gets codegen'd. Then you can query it directly or use a UI to generate queries.
Both of these seem to work nicely but they're pretty limited use cases.
My experience with Prolog at university was that it was pretty fun but there's just no way I would wanna use it for anything that isn't inherently Prolog-shaped. As soon as we were implementing nontrivial stuff in it the abstraction leaked like a sieve and you felt mostly like you were hacking against the backtracking algorithm rather than taking any actual advantage of the language.
- xlii 3y agoYeah, Gerrit predicates being deprecated are (in my opinion) sign how hard it is to convince people to use Prolog. If people maintaining Gerrit cannot use it (and probably there was push at Google too), then how to convince The Median Dev...?
- hanwenn 3y agoNot sure what "push at Google" means. For full context: the idea to use Prolog came from the project founder. In retrospect, it was a terrible idea, because almost nobody knows or likes Prolog, and that includes the SWEs at Google both on my team, and the ones configuring Gerrit. (I run the team that works on Gerrit at Google.)
- ahefner 3y agoI understand in practice that "nobody knows or likes Prolog" is a valid criticism, but was it a sound idea technically?
- bbor 3y agoI'd say "we don't have the human resources to support the development of this system in the long term" to be a pretty valid technical reason. Remember that we're engineers, not scientists -- the goal is efficacy
- hanwenn 3y agoSubmit blocking is not only a feature targeted at admins (they configure how submit criteria), but also for users: users have to know if their change is ready to be submitted. IIRC, The result of a failing Prolog rule was a single string, which would surfaced to the user. It was often impossible for users to understand why that condition triggered and what they could do to address the issue. On a technical level the idea was also flawed. The Prolog interpreter had to be constrained (to avoid infinite loops), with hardcoded recursion limit. This meant that adding one Prolog rule too many could trigger a failure in the interpreter which would then throw 5xx errors and wedge the server.
- YeGoblynQueenne 3y ago>> The Prolog interpreter had to be constrained (to avoid infinite loops), with hardcoded recursion limit. Oh well that sounds like bad coding, definitely. You may run into that sort of problem -infinite recursions- the first few times you code in Prolog but you learn to avoid it, just as you learn to avoid infinite do-while loops etc. Btw, since you mention the server being wedged, a few years ago I was working at a C# shop and there was an incident where _all_ our deployments died because of an infinite iteration. Some code was missing its exit condition from the loop and since this was on our platform which had the common functionality, it affected all our clients. There was a meeting upstairs, inevitably. When the development team head returned from the meeting he told us that he had explained what happened and the upstairs had decided that we should no longer use iteration because it risked going haywire, as we had just seen. The alternative? Use recursion instead. In C#. Obviously nobody ever complied with this stupid idea. But you can bring down a bunch of servers very easily in any language you like. Another time, in the same company, there was an infinite recursion now, created in the web templating language we used, an in-house version of django. That was a bit unexpected. In another job, I got some gentle ribbing from colleagues for sucking up all the juice from the database servers with an inexpertly written SQL script. And so on. I mean, people say sometimes that all that stuff about the halting problem is purely theoretical and so on, but then non-termination bites you in the boogies and you're left with egg on your practically-minded, results-oriented face.
- 3y ago
- xlii 3y agoWhat I mean by it: Someone advocated for the solution (it ended up part of a product) and since now it's deprecated those advocacy efforts weren't successful enough to induce adoption. By your words there seemed to be only a single person, but from outsider's viewpoint its impossible to say how big push there was. "Nobody knows or likes Prolog" is exactly the reason why I refrain from using Prolog in professional environment. I can use it, I like it, but unless I have full team of people committed it's an empty effort (even harmful). So yeah, if smart people failed to convince other smart people, there's something wrong with it. And in my view is people don't get to like it because current sources aren't good enough. There is documentation but it's not clear what the target solution scope is (and rarely people professionally implement Sudoku solvers), what the benefits are and what are the success stories.
- YeGoblynQueenne 3y ago>> So yeah, if smart people failed to convince other smart people, there's something wrong with it. Maybe those weren't very smart people, after all? I mean we only have Google's assurances to go by, that they are the place where brilliant people go to feel mediocre etc, but doesn't that sound like a pick-up line, that would put off most people who don't consider themselves dumb? Also: a good engineer never blames her tools.
- tannhaeuser 3y agoSo what is the replacement for Prolog as language for commit rules in Gerrit? Some Java DSL such as Drools, seeing as Gerrit went from Python to Java (and supposedly from gwt to other toolkits since)? Or some ad-hoc scripting for whatever language is used by the codebase managed in Gerrit (such as idk checkstyle for a Java-based project?). The latter case would be kindof understandable since templates/common configs for checkstyle (and alternative systems) are very common. But I'd imagine a Java parser in Drools would be infeasible compared to Prolog, and in any case absolutely unmaintainable. Maybe the problem was that the Java parser wasn't updated for current Java versions? I don't know, since nobody is using Gerrit for self-hosted git management compared to gitlab, bitbucket, and co. Without context, the argument "nobody knows Prolog" is pretty lame tbh, especially coming from Googlers.
- hanwenn 3y agoOne can write conditions using the search query language, see https://gerrit-review.googlesource.com/Documentation/config-submit-requirements.html#examples https://gerrit-review.googlesource.com/Documentation/config-...
- YeGoblynQueenne 3y agoI've coded in Prolog since 2008-9, mostly for fun until 2017 when I started my PhD in Inductive Logic Programming (basically, machine learning of Prolog programs). I've coded almost exclusively in Prolog since then [1]. I've even used it professionally in two jobs in the past year, although I left both early, and now I'm doing a post-doc in explainable machine learning for robotics, again with Prolog (ILP, really). All this to say that I've worked on a few substantial, non-trivial software projects in Prolog and I can say with confidence that "the abstraction" does not "leak like a sieve", like you say. It's bad programming practices that leak like a sieve. You can get in a real mess in Prolog if you are not careful. But you can get in a real mess with OOP if you're not careful, as e.g. in the object-relational impedance mismatch. One of the projects I worked on in one of the two jobs I mention above was indeed a complete mess. But not because of Prolog: because of people who copy/pasted code left-and-right and puked spaghetti on the source file completely oblivious of the need to, one day, maintain their mess. Again, nothing that Prolog is particularly guilty of. Remember: programming languages don't kill projects; programmers kill projects. _________ [1] I've become like the proverbial FORTRAN programmer: when I tried coding in Python it came out all Prolog-like. Bad idea. Python doesn't have tail-call optimisation by default.
- bw86 3y agoDo you have any hints how to use Prolog in a way to avoid making a mess? Which Prolog implementation(s) did/do you use?
- YeGoblynQueenne 3y agoDo I have any hints? Oh dear. The advice in this technical report is sound: Coding Guidelines for Prolog https://arxiv.org/abs/0911.2899 https://arxiv.org/abs/0911.2899 It goes over some style matters but also makes more practical recommendations about using the language for best results. I have followed those guidelines in the last few years, often before reading the book, and they have generally served me well. My own, very personal advice is to avoid the dynamic database as if it was the plague. To clarify, the "dynamic database" refers to the use of assert/1, retract/1 and friends to add to, and remove clauses from the program database. Prolog programs are stored in a relational database and since we can open it up, write new program clauses to it, and compile it again, we call it the "dynamic database". Well, it may be dynamic, but it is also evil. Every time I use it, I end up hurting myself. So I've learned to hurt myself before I ever use it, just because that saves me most of the later pain. In my current project I found myself going to great lengths to avoid using the dynamic database. For example, I have some code that auto-generates predicates to access the elements of a list that represents the state of the world as perceived by an autonomous agent guiding a robot. These "access predicates" look like this: inspect(map_area,map_area(X_min,X_max,Y_min,Y_max),[map_area(X_min,X_max,Y_min,Y_max),_,_,_,_,_]). inspect(scan_area,scan_area(X_min,X_max,Y_min,Y_max),[_,scan_area(X_min,X_max,Y_min,Y_max),_,_,_,_]). inspect(position,position(X,Y,Theta),[_,_,position(X,Y,Theta),_,_,_]). inspect(observations,observations(Contacts,Count),[_,_,_,_,observations(Contacts,Count),_]). inspect(grouped_observations,grouped_observations(Groups,Count),[_,_,_,_,_,grouped_observations(Groups,Count)]). % etc. Here, the list that represents the state-vector is the last argument of inspect/3 and its terms can be inspected by passing an initialised state-vector list to that argument. For example: ?- initialised_state_vector(_Vs), inspect(position,P,_Vs). P = position(x(0.0), y(0.0), theta(0.0)). Modification operations work in a similar way: modify(position,increment,x,[Map_area,Scan_area,position(X,Y,Theta),Scan_params,Observations,Grouped_observations], [Map_area,Scan_area,position(X_,Y,Theta),Scan_params,Observations,Grouped_observations]) :- increment_float(X,X_). modify(position,decrement,x,[Map_area,Scan_area,position(X,Y,Theta),Scan_params,Observations,Grouped_observations], [Map_area,Scan_area,position(X_,Y,Theta),Scan_params,Observations,Grouped_observations]) :- decrement_float(X,X_). % etc. And then I can do: ?- initialised_state_vector(_Vs1), modify(position,increment,x,_Vs1,_Vs2), inspect(position,P,_Vs2). P = position(x(0.1), y(0.0), theta(0.0)) ; false. All this is to avoid writing the terms in the state-vector (like position(X,Y,Theta)) to the dynamic database, then using asserts and retracts to modify them, which is the obvious thing to do. What I did above is also a more efficient way to access the elements of the state-vector list by unification, instead of having to scan the list to find a term (which can add up to a lot of scanning in the project I'm working on). Using asserts is also costly (but clauses can be accessed fast once asserted). The hitch is that some of the terms in the state-vector above have arguments that are themselves lists and those lists need to be accessed to inspect or modify them. Which means scanning a list again. So I added clauses of inspect predicates that look like this: inspect(group,GroupId,group(GroupId,Contacts,Count),[group(GroupId,Contacts,Count)|_]). inspect(group,GroupId,group(GroupId,Contacts,Count),[_,group(GroupId,Contacts,Count)|_]). inspect(group,GroupId,group(GroupId,Contacts,Count),[_,_,group(GroupId,Contacts,Count)|_]). inspect(group,GroupId,group(GroupId,Contacts,Count),[_,_,_,group(GroupId,Contacts,Count)|_]). inspect(group,GroupId,group(GroupId,Contacts,Count),[_,_,_,_,group(GroupId,Contacts,Count)|_]). So that I can access the elements of a list-argument at constant time. So that's effectively compiling a Prolog list to act as an array, or a dictionary I guess. I don't know how big the "compiled" lists have to be, so I set a configurable "budget" before I generate the access predicates above and hope for the best. An alternative would be to simply add more inspect clauses for list-arguments as needed by using asserts but that's only going to happen over my cold, dead body. All this could have been done much more simply if I used assert/retract, and also used Prolog lists as they're intended to be used, as flexible linear-time access structures. But if I did that, I'd end up in a world of pain later on. I know that from experience and I have the scars to show for it. I suppose my approach could be seen as jumping through hoops to do something that is easy in other languages - just write some stuff to a database. But, I've worked with OOP languages on backends accessing relational databases all the time I was in the industry, and it's anything but easy. It's a constant source of pain instead: somehow every OOP textbook I've ever read forgets to tell you this, but OOP languages are simply not good at handling data. In Prolog at least my backend and my database are one and the same, my code _is_ my database, and I can has a clean and tidy representation where my entire program's state is in the source code (rather than spread out between the source and the database, and between the source and the runtime). So it takes a bit of work. And what doesn't? My scheme above also serves to preserve the "logical purity" of Prolog, since accessing the state-vector is side effects-free, but that was really not my motivation. I don't care about purity. However, in Prolog, when you leave the declarative, logical, immutable paradigm behind and enter the world of destructive data structure updates, you enter a world of pain. The dynamic database is evil. OK, so this got a bit too long, by far. You asked for a "hint" and I had to go and write a little white paper as usual. But I hope all that is useful to you, as a kind of case study. Edit: I use SWI-Prolog. It's free and it's got the most libraries. Also a helpful community and a main developer who is clearly superhuman.