logoalt Hacker News

jmmcdlast Wednesday at 2:05 PM16 repliesview on HN

The best example of all is Prolog. It is always held up as the paradigmatic representative of logic programming, a rare language paradigm. But it doesn't need to be a language. It is really a collection of algorithms which should be a library in every language, together with a nice convention for expressing Prolog things in that language's syntax.

(My comment is slightly off-topic to the article but on-topic to the title.)


Replies

bux93last Wednesday at 4:27 PM

The main thing about prolog isn't the algorithms. In fact, the actual depth-first search isn't even part of the standard.

The nice thing about prolog is that you write logical rules, and they can get used in whatever order and direction that is needed. By direction, I mean that if you define "a grandparent is the parent of a parent", you can now use that rule not just to evaluate whether one person is a parent (or to find all grandparents) but also to conclude that if you know someone is a grandparent, and they are the parent of some one, then that person is someone's parent. Ok, it can also do recursion, so if you define an ancestor as a parent or the parent of an ancestor it will recurse all the way up the family tree. Neat.

You could write some kind of runtime that takes c code and brute-forces its way from outputs to inputs, except that regular imperative code allows for all kinds of things that make this impossible (e.g. side-effects). So then, you'd be limited to some subset, essentially ending up with a domain specific language again, albeit with the same syntax as your regular code, rather than those silly :- symbols (although LISP looks much sillier than prolog IMHO).

What the article is getting at is that if you use some features specific to a language, it's hard to embed your code as a library in another language. But is it? I mean, DLLs don't need to be written in the same language, there's stuff like JNI, and famously there's stuff like pytorch and tensorflow that runs CUDA code from python.

show 3 replies
tannhaeuserlast Wednesday at 5:36 PM

The syntax of Prolog is basically a subset of the language of First Order Logic (sans quantifiers and function symbols), it doesn't get any more minimal than that. What's special in Prolog compared to imperative languages including functional languages is that variables aren't "assigned" but implicitly range over potential values until satisfying the context, like in math formulas for sets. Yes you can express that awkwardly with tons of type annotations and DSL conventions so that you never have to leave your favourite programming language. But then there's the problem of a Prolog "engine" doing quite a bit more than what could be reasonably assumed behind a synchronous library call, such as working with a compact solution space representation and/or value factoring, parallel execution environment, automatic value pruning and propagation, etc.

The integration of a Prolog backend into a mainstream stack is typically achieved via Prolog code generation (and also code generation via LLMs) or as a "service" on the Prolog side, considering Prolog also has excellent support for parsing DSLs or request/responses of any type; as in, you can implement a JSON parser in a single line of code actually.

As they say, if Prolog fits your application, it fits really well, like with planning, constraint solving, theorem proving, verification/combinatoric test case enumeration, pricing models, legal/strategic case differentiation, complex configuration and the like, the latter merely leveraging the modularity of logic clauses in composing complex programs using independent units.

So I don't know how much you've worked hands on with Prolog, but I think you actually managed to pick about one of the worst rather than best examples ;)

show 2 replies
RHSeegerlast Wednesday at 3:21 PM

By that same logic, we don't need object oriented features in a language, because we have closures and can get the same functionality with a library.

Sometimes, having a language with a distinct syntax is nicer.

show 3 replies
JoelMcCrackenlast Wednesday at 3:57 PM

The only languages I know that can do prolog-like-constructs as-a-library are lisps, or at least langs that have reasonable symbol constructs. Usability is way way worse if you can’t talk about variables as first class objects.

I was talking to Bob Harper about this specific issue (context was why macro systems are important to me) and his answer was “you can just write a separate programming language”. Which I get.

But all of this is just to say that doing relational-programming-as-a-library has a ton of issues unless your language supports certain things.

show 1 reply
somatlast Thursday at 7:00 AM

Speaking of prolog, any recommendations for resources learning it at a stage somewhere between "draw three circles" and "draw the rest of the owl"

I don't have real work I need prolog for, but I find it an interesting subject, My personal learning goal, the point where I can say I know prolog reasonably well is when I can get it to solve this mit puzzle I found, a sort of variant of soduku. I found a clever prolog solver for soduku that I thought could teach me more in this domain, but it was almost to clever, super optimized for soduku(it exploited geometric features to build it's relationships) and I was still left with no idea on how to build the more generic relationships I need for my puzzle(specific example if soduku cells were not in a grid how could they be specified?), in fact I can find very little information on how to specify moderately complex, ad hoc relationships. One that particularly flummoxed me was that some rules(but you don't know which) are wrong.

https://www.swi-prolog.org/pldoc/man?section=clpfd-sudoku

show 5 replies
jandreselast Wednesday at 6:40 PM

Prolog is great because when it works it feels like magic. You give it some pragmas and it tells you the answer. The downside is when it doesn't work it also feels like magic. It's not easy to reason about the amount of work it needs to do. If your Prolog program is taking a long time to run it is hard to figure out if it is going to take 2 hours or 4,000 millennia.

slaymaker1907last Wednesday at 2:54 PM

I think the examples others have highlighted show the problem with just making it a library. They’re all lacking a lot of features from Prolog, particularly in terms of optimization. Just use Prolog if you need its features and invoke SWI-Prolog like you’d call any other language’s interpreter.

show 1 reply
bwestergardlast Wednesday at 2:23 PM

Are there any particularly excellent examples of prolog implemented as a library you could point us to?

show 6 replies
f1shylast Thursday at 11:11 AM

Disclaimer: I've no idea what I'm talking about. :)

But I have heard repeatedly that the good thing of prolog is the compiler, that takes information and queries that would be awful inefficient, and convert them in something that actually works. So I'm not sure... of course, you can convert virtually any language in a kind of library with some API that basically accepts source code... but I'm pretty sure is not what you meant.

rienbdjlast Wednesday at 7:20 PM

Think of Prolog the language as just a serialization of a Prolog AST. The AST could be constructed in any programming language as a library. But what if we want to share and store these ASTs? We can serialize them to Prolog the language! The language has value even if it’s a library.

zahlmanlast Thursday at 5:10 AM

Prolog admittedly mystifies me even more than the Haskell family. How do you do anything effectful, like read from a file, or output arbitrary data to standard out, or set up a loop to process keyboard events every 1/n seconds? How do you make system calls?

show 1 reply
nine_klast Wednesday at 7:03 PM

Prolog is a contrived example. It's small and simple enough to be implemented as a DSL embedded in another language, reusing most of the parser and leaningn its execution logic.

Now try to produce a library that adds compile-time features: static types, lifetimes, the notion of const and constexpr, etc. You can, of course, write external tools like mypy, or use some limited mechanism like Java annotations. But you have a really hard time implementing that in an ergonomic way (unless your language is its own metalanguage, like Lisp or Forth, and even then).

Creating a library that alters the way the runtime works, e.g. adding async, is not entirely impossible, but usually involves some surgery (see Python Twisted, or various C async libs) that results in a number of surprising footguns to avoid.

Frankly, even adding something by altering a language, but not reworking it enough to make the new feature cohesive, results in footguns that the source language did not have. See C#'s LINQ and exceptions.

ModernMechlast Wednesday at 3:12 PM

But why should it be though? You haven’t really addressed that. It’s like saying “Haskell shouldn’t be its own language, it should just be a couple of features like lambdas integrated into a JavaScript library”. Well if you do that you get some nice features in JavaScript but you’ve done away with the whole value proposition of pure functional programming. That’s an actual loss, there’s something to be said for maintaining a pure set of features that gives languages different properties and guarantees you can’t get with “everything is just a lib to an imperative language”

show 1 reply
DonHopkinslast Thursday at 1:44 PM

How many Prolog programmers does it take to change a lightbulb?

false.

https://www.j-paine.org/dobbs/prolog_lightbulb.html

I always wanted to write a compiler whose front-end consumes Prolog and back-end emits PostScript, and call it "PrologueToPostscript".

prologue: a separate introductory section of a literary, dramatic, or musical work.

postscript: an additional remark at the end of a letter, after the signature and introduced by ‘PS’.

pjmlplast Wednesday at 3:17 PM

Except when implemented as library it doesn't take advantage of WAM and related JIT.

chiilast Wednesday at 2:23 PM

i treat it like i treat SQL.