Factually, it is more legible, maintainable, easy to extend. However, imo, this is mostly because all of the I/O had been abstracted away.
In the python program, I/O and logic were interspersed in a way that made it difficult to reason about only one or the other. You have to understand our data models to understand the code, and vice versa.
If I were to rewrite the python program today, it would "look" a lot like the Prolog one, and probably be equally as legible and maintainable.
I think it's an example where Prolog (as a "logic" language) "shepherds" you do the right thing with respect to I/O separation. I imagine if I tried writing it in Haskell or OCaml, the effect would be similar. I'm reminded of this article: https://news.ycombinator.com/item?id=22696229.
Python, meanwhile, is a blank canvas and a full set of paints, which is its great strength in experienced hands, but also its great downfall. When I leave the company, there's nothing stopping another engineer (a junior, or even an experienced engineer with different skill trees) from rewriting things in a way that "works" but compromises legibility or extensibility.
With discipline, you can develop a program in Python that looks quite similar to the Prolog one, but the only guardrails against writing it in spaghetti is psychological.
In any case, it was a fun exercise. It makes me want to try writing more things in different languages, if for no other reason than to improve my usage of the subset of Python I like best. :)
My favorite gem, especially before python3 and typehinting were more widely in-use, is attrs [0]. It allows you to define rich data types (which python is great for) in a declarative/expressive/legible manner (which python sometimes isn't great for).
imo, it's a fantastic example of how metaprogramming allows libraries to actually enhance a language. Another one that demonstrates the power of MP is fire[1], a tool that allows you to drive classes with a MP-generated CLI.
[0] https://www.attrs.org/en/stable/examples.html [1] https://github.com/google/python-fire
I don’t know much of CSPs to know whether Knuth’s Dancing Links or his DLX was used all that often for them. I’m guessing an exact cover problem is one such CSP, but it seems that CSPs also use backtracking which it seemed to me that Dancing Links and sparse matrices were a good combo for that. Anyone have thoughts or inputs or corrections on whether what I said is correct about CSPs?