Live data from Hacker News

Prolog Basics Explained with Pokémon

unplannedobsolescence.com

41–50 of 64 posts

Re: Prolog Basics Explained with Pokémon

#41
A while ago I was playing the romhack Run&Bun, which drastically ups the difficulty of Pokemon Emerald. Watching others play, most of the game was doing 'calcs': calculating how to approach a battle. This was done using a javascript frontend to a simulator, and a lot of excel sheets.

So I forked the calculator and added a Prolog wrapper so I could find solutions to battles based on the team of Pokemon that I caught. https://github.com/deosjr/runbuncalc/blob/master/main.pl

My runs died pretty early, but there are some notes here as I was implementing that are fun to read. I implemented each battle as a test case and let my solver find a solution, then amended the plan and commented on what actually happened. For example: https://github.com/deosjr/runbuncalc/blob/master/run10.pl#L2...

Re: Prolog Basics Explained with Pokémon

#42

Love this use case, makes me want to implement something similar for Magic the Gathering. I love using scryfall, but I think a more cli first approach with descriptive rules would suffice much better for brewing in eternal formats like Commander with ever growing card pools. I mostly work off of keyword search.

This might be your jam. I should revisit this, most of it is unimplemented. But the parsing part was interesting, since MTG has such a codified language for explaining the rules. My idea here was to take a card's rules text from the official API and parse it into smth that can be used in the game, so you could keep up with new sets with implementation. The weird rule-breaking edge cases will always fail, but a large set of design space can fit, I think.

See https://github.com/deosjr/pmtg/blob/master/parse.pl

Re: Prolog Basics Explained with Pokémon

#45

Earlier quoted context omitted.

Importantly, Datalog is not Turing-complete though.

You can get Turing completeness by wrapping your datalog query in a while loop, so that's not particularly restrictive.

It’s surprisingly hard to design a useful language which isn’t Turing-complete, so it should be seen as a compliment, not a problem to fix

Re: Prolog Basics Explained with Pokémon

#46
post #38

Earlier quoted context omitted.

> as soon as you do something actually complicated, you realize that the different optimization modes of the engine give different results The same is true of SQL query planners. You can perform basic queries without understanding how your SQL engine of choice works under the hood, but if you want performance, you must understand how your DB works. SQL is just the interface. This is different in kind from imperative…

Yeah, but the difference is that SQL provides a huge number of ways to solve the "My query got slow when it got complicated" problem. In Prolog, you have the cut operator, and when that stops working for your usecase, you're just SOL.

I relate to "I wrote it in Prolog, it works on a test example, it doesn't work on the full thing and I don't know if it will ever finish", and that was why I stopped my last attempt at Advent of Code in Prolog. It took me hours longer to make something which worked, it was more code, and it never finished on the full puzzle, and I was fed up and had no motivation or approach to discovering why.

But I think it's different in experience, but not different in kind, from knowing that in Java and C# and Python, string catenation in a loop will perform badly and generate a lot of garbage collection pressure, and you need to know about either StringBuilder or the pattern of making a List of chunks then converting to string once at the end, to get better performance. Or in PowerShell, Objects have more convenience but a lot more overhead than simple values and you have to reach for .NET Library functions for better performance. Neither of those is a problem in C, but not because C has solved those problems, but because C doesn't have any conveniences. Any language that has higher level conveniences, have them implemented in some way with some assumptions that will have tradeoffs that you need to understand to use it well, and the higher it is, the more things there are to know - but also the shorter convenience code you can write.

Still, though, the claim that all Prolog has is the cut operator is not right. If you write a linear list scan it will be O(N), and if you put two of them together it will be O(NxN) just like in any language, e.g:

    member(X, Items),
    member(Y, Items),
If you can put your lookups into a Trie instead of a list, they will be faster. SWI Prolog ships with libraries for Tries, Association Lists, Red-Black trees, and other things. Fundamentally, code with functions and scopes and branches is tree-shaped, and code describes tree-shaped execution patterns (see the beginnings of Structure and Interpretation of Computer Programs, SICP, I think), and Prolog "cut" trims branches from the tree, but if you rewrite your code so it doesn't describe branches of the tree that you don't want to execute, then you don't need to cut them and your code has less runtime (in any language).

SWI Prolog has tabling (memoization)[1] which you can wrap around any predicate with one line, and the engine will cach the results for faster lookups. You can write this in other languages, e.g. with Python decorators, but you have to write it yourself instead of it being included.

SWI and Scryer have constraint solvers, which are basically another language embedded in Prolog using its programmable syntax, backed by a different search engine, that can solve numerical problems with constraint propagation much faster than with Prolog normal search - something that just isn't possible in other languages in the same way, only available as library code (e.g. Z3 constraint solver), and not a standard techniqe.

SWI Prolog has compare/3 and zcompare/3 e.g. "compare(Op, 4, 5)" will fill in the operator Op = SWI Prolog ships with a graphical profiler, too: https://www.swi-prolog.org/pldoc/man?section=profile

[1] https://www.swi-prolog.org/pldoc/man?section=tabling-memoize

Re: Prolog Basics Explained with Pokémon

#47

When i was in uni, the course teaching Prolog and Lisp was called "Artificial Intelligence for Engineers".

I’ve always heard the first wave of AI was all lisp. Why is that? Just cause it had superpowers over the other languages of the day?

I can see why someone would think prolog could bring an AI wave. Even after messing around with it for a few hours, I feel like there are things I could build in prolog that I couldn’t build in typescript.

Re: Prolog Basics Explained with Pokémon

#48
post #30
post #29

Earlier quoted context omitted.

In other languages, you can find the lines where the performance problems are and fix them without breaking the abstraction everywhere else.

I think this is very well phrased, and I would argue the same holds for Prolog too. In my opinion, a key difference between Prolog and other languages in that regard is one of degree, not kind: Compared to other languages, addressing performance problems in Prolog engines tends to have far greater effects on Prolog programs, because so much is implicit (i.e., left to the engine). If the performance problem is not in…

> "How to formulate the program better, is there a better approach altogether?"

When I code an imperative Bubble Sort, a profiler can identify that function as a hotspot and I can Google "faster sort algorithm" and can understand relatively easily that the nested linear scans were taking the time. In recent years, Casey Muratori has become a prominent internet voice against naive use of "Object Oriented" (OOP) patterns, because using a lot of OOP inheritance and abstraction adds a little overhead here and there and everywhere, leading to poor overall performance with no single place to speed it up.

My Prolog code is closer to the OOP situation, especially when I try to express something with a DCG. It is easy to accidentally code non-deterministic searches in places where I did not expect, or desire them, in a way which makes the whole code describe a huge search space and there is no single place where the extra runtime is localised and no good way to incrementally improve the situation. The comparison in your link between Gecode and Scryer is illustrative; the author wrote a solution in Gecode which completed in 10 seconds. They spent "many hours" writing Prolog and they cannot get the code to finish on the large case, they don't understand why, and they have no way forwards except to ask the internet. Likely there is no single part which is slow in the way that Bubble Sort is slow, only "there may be better approaches altogether" - but how can the author help themselves find and move towards the better approaches? "Learn a faster sorting algorithm" is a practical, achievable, step forwards; "just be a better programmer" is an impassé.

The sticking point is that with OOP patterns, the question of "how do I become a better programmer?" often does not need any answer, because the layers of indirection are additive, each call adds some milliseconds, and that overall leads to a program that still works in a reasonable time, it merely feels sluggish or has a tedious delay. With Prolog, the calls can quickly become a combinatorial explosion of search space, leading to a program which does not finish at all, and thus the question needs an answer. With an imperative codebase a suggestion to "use a faster algorithm for this one task" is one step along a lifetime of gradually becoming a better programmer. With OOP abstractions, people can get results, solve problems, or be employed making slow web portals without ever improving or making highly performant code. With Prolog "You simply have to be a better programmer" before you can get any results at all on larger cases is a much steeper learning curve.

Re: Prolog Basics Explained with Pokémon

#49

> " Don't be bothered with by the fact that the solutions end with "or false" here. It's a function of how the search algorithms work; the solver looked for more solutions, then failed. I'll admit, I don't totally understand why it only sometimes does this, but it's expected. " I think this is explained in The Power of Prolog[1] that the answers coming from Prolog are not printing text to a terminal, they are valid P…

[deleted]

Re: Prolog Basics Explained with Pokémon

#50

Love this use case, makes me want to implement something similar for Magic the Gathering. I love using scryfall, but I think a more cli first approach with descriptive rules would suffice much better for brewing in eternal formats like Commander with ever growing card pools. I mostly work off of keyword search.

I'm not as familiar with Magic, but I've always been curious if that community has tooling at a comparable level of maturity to Pokemon Showdown.

For Yu-Gi-Oh! You have ygopro
Post reply on HN