Live data from Hacker News

Can logic programming be liberated from predicates and backtracking? [pdf]

www-ps.informatik.uni-kiel.de

51–60 of 102 posts

Re: Can logic programming be liberated from predicates and backtracking? [pdf]

#51
post #23
post #10

Earlier quoted context omitted.

isn't backtracking a complete search strategy?

Depth first search is not complete if branches can be infinitely deep. Therefore if you're in the wrong infinite branch the search will never finish. Breadth first search is complete even if the branches are infinitely deep. In the sense that, if there is a solution it will find it eventually.

Reminds me that Warren made a talk about prolog term domains to study resolution over infinite branches.

Re: Can logic programming be liberated from predicates and backtracking? [pdf]

#52
post #37

Earlier quoted context omitted.

Hrm. I guess the converse applies if nodes can have infinite children. That said, even if your tree is infinitely wide and deep, we're only dealing with countable children, right? Thus a complete traversal has to exist, right? For example, each node has unique path to root, so write where each ni is the sibling ordinal of the node at depth i in that path, i.e. it's the ni-th sibling of the n(i-1)st node. Raising each…

No breadth first search is still complete given an infinite branching factor (i.e. a node with infinite children). "Completeness" is not about finishing in finite time, it also applies to completing in infinite time. Breadth first search would visit every node breadth first, so given infinite time, the solution would eventually be visited. Meanwhile, say a branch had a cycle in it, even given infinite time, a naive d…

> "Completeness" is not about finishing in finite time, it also applies to completing in infinite time.

Can you point to a book or article where the definition of completeness allows infinite time? Every time I have encountered it, it is defined as finding a solution if there is one in finite time.

> No breadth first search is still complete given an infinite branching factor (i.e. a node with infinite children).

In my understanding, DFS is complete for finite depth tree and BFS is complete for finite branching trees, but neither is complete for infinitely branching infinitely deep trees.

You would need an algorithm that iteratively deepens while exploring more children to be complete for the infinite x infinite trees. This is possible, but it is a little tricky to explain.

For a proof that BFS is not complete if it must find any particular node in finite time: Imagine there is a tree starting with node A that has children B_n for all n and each B_n has a single child C_n. BFS searching for C_1 would have to explore all of B_n before it could find it so it would take infinite time before BFS would find C_1.

Re: Can logic programming be liberated from predicates and backtracking? [pdf]

#53

Earlier quoted context omitted.

In practice, though, with BFS you'd run out of memory instead of never finding a solution. Also, there shouldn't be many situations where you'd be able to produce infinite branches in a prolog program. Recursions must have a base case, just like in any other language.

This has to do with the ordering of search: searching a proof tree (an SLD tree, in SLD-Resolution) with DFS, as in Prolog, can get stuck when there are cycles in the tree. That's especially the case with left-recursion. The article gives an example of a left-recursive program that loops if you execute it with Prolog, but note that it doesn't loop if you change the order of the clauses. This version of the program, t…

IIRC Markus Triska showed a trick (with a nickname i forgot) to constrain the search space by embedded a variable length into the top level goal.

Re: Can logic programming be liberated from predicates and backtracking? [pdf]

#54
post #48

Earlier quoted context omitted.

Suppose you have a node with two children A and B, each of which has infinitely many children. If you performed an ordinary BFS, you could get trapped in A's children forever, before ever reaching any of B's children. Or, suppose that a node has infinitely many children, but the first child has its own child. A BFS would get stuck going through all the first-level children and never reach the second-level child. A BF…

Countable infinity does not work like that: two countable infinities are not more than one countable infinity. I think it falls into the "not even wrong" category of statements. The Wikipedia article is fairly useful: https://en.wikipedia.org/wiki/Countable_set

Yes, if you put two (or three, or countably many) countable sets together, you obtain a set that is also countable. The problem is, we want to explicitly describe a bijection between the combined set and the natural numbers, so that each element is visited at some time. Constructing such a bijection between the natural numbers and a countably-infinite tree is perfectly possible, but it's less trivial than just DFS or BFS.

If we're throwing around Wikipedia articles, I'd suggest a look at https://en.wikipedia.org/wiki/Order_type. Even if your set is countable, it's possible to iterate through its elements so that some are never reached, not after any length of time.

For instance, suppose I say, "I'm going to search through all positive odd numbers in order, then I'm going to search through all positive even numbers in order." (This has order type ω⋅2.) Then I'll never ever reach the number 2, since I'll be counting through odd numbers forever.

That's why it's important to order the elements in your search strategy so that each one is reached in a finite time. (This corresponds to having order type ω, the order type of the natural numbers.)

Re: Can logic programming be liberated from predicates and backtracking? [pdf]

#55
post #3

Man, lately, I feel like this stuff has been following me around. I'd really like to deep-dive into logic programming and related paradigms. Just recently came across Answer Set Programming[0] (via Potassco's clingo[1]), and it has made me realize just how ignorant I am of the design space that's being explored here. More personally, I recently spent enough time with first Scheme and then APL that the paradigms click…

I'm literally using ASP and Clingo to do logic programming for school. And you're telling it became relevant to you in your work??

I use ASP at work! I used it as the core of a powerful code generator: I modeled the type system I wanted to implement, some base operations and derivation rules, and had it synthesize implementations for every possible operator between every possible pair of types. I run clasp and it dumps out thousands of lines of C# implementing a simple symbolic matrix linear algebra library. It's one of the most beautiful things I've made, imo.

Re: Can logic programming be liberated from predicates and backtracking? [pdf]

#56
post #41

Earlier quoted context omitted.

It isn't. I do most of my programming in Prolog, I write oodles of it daily, and it's not a problem. You learn to think that way easily. The argument is basically that Prolog is not 100% declarative and that if we jump through a few hoops, and translate it all to functional notation, we can make it "more declarative". But let's instead compare the incomplete declarativeness of Prolog to a fully-imperative, zero-decla…

Serious question, how do you deal with typos in functors? And is your techniques specific to the implementation of Prolog you use? Recently I had a maddening experience chasing this down: result(World0, move(robot(R), Dir), World) :- dissoc(World0, at(robot(R), X0), World1), direction_modifier(Dir, Modifier), X #= X0+Modifier, conj(World1, at(robot(R), X), World). result(World0, drop_rock(robot(R), Place), World) :-…

[deleted]

Re: Can logic programming be liberated from predicates and backtracking? [pdf]

#57
post #41

Earlier quoted context omitted.

It isn't. I do most of my programming in Prolog, I write oodles of it daily, and it's not a problem. You learn to think that way easily. The argument is basically that Prolog is not 100% declarative and that if we jump through a few hoops, and translate it all to functional notation, we can make it "more declarative". But let's instead compare the incomplete declarativeness of Prolog to a fully-imperative, zero-decla…

Serious question, how do you deal with typos in functors? And is your techniques specific to the implementation of Prolog you use? Recently I had a maddening experience chasing this down: result(World0, move(robot(R), Dir), World) :- dissoc(World0, at(robot(R), X0), World1), direction_modifier(Dir, Modifier), X #= X0+Modifier, conj(World1, at(robot(R), X), World). result(World0, drop_rock(robot(R), Place), World) :-…

>> Right now this seems to have all the downsides of programming exclusively with "magic strings", and I haven't been able to find any cure for it or even seen this problem discussed elsewhere.

The cure is to not try to program with "magic strings". You don't need to, and if you really want to, then you should try to understand what exactly it is that you're doing, and do it right.

Specifically, what you call "magic strings" are what we call "functions" in First Order Logic, and that Prolog calls compound terms, like carring_rock(robot(R)) which is in fact two compound terms, nested. Prolog lets you nest compound terms infinitely and if you really want to hurt yourself, one great way to do it is to nest terms everywhere.

The alternative is to understand that when you use compound terms as arguments to predicates (or other terms) you are really _typing_ those arguments. Above, "carring_rock(_)" is the type of the second argument of result/3, and "robot(_)" is the type of the single argument of carring_rock/1. The catch is, of course, that Prolog is not a typed language and it doesn't care if you want to hurt yourself. So if you need to have types like that, then you should write some code to explicitly handle types and do some type checking. For instance, right out the top of my head:

  result_type(T):-
      T =.. [carring_rock,R]
      ,robot_type(R)
      ,!.
  result_type(T):-
      throw('Unknwon result type':T)
  
  robot_type(T):-
      T =.. [robot,R]
      , % ... further typing of R
      ,!.
  robot_type(T):-
      throw('Unknown robot type':T)
Note that this is not the right way to throw errors but I can't now.

A simpler thing I'd advise, but that's going into style territory, is to keep variable names as short as possible. One reason it's hard to spot the mistake in the code above is that the source code is all cluttered with long variable names and the nesting of compound terms makes it even more cluttered. An IDE with good syntax highlighting can also help. Perversly, I find that there are many people who code in Prolog either without syntax highlighting at all or in IDEs that are not aware of common results of typos, like singleton variables. The SWI-Prolog IDE is good for this and Sweep for Emacs has a good reputation also (although I haven't tried it):

https://eshelyaron.com/sweep.html

Edit: it just occurred to me that the project I'm working on currently, in my post-doc, involves quite a bit of typing using compound terms as arguments, like you do above. I've opted for a program synthesis approach where the predicates I need with typing are automatically generated from a specification where I define the arguments of predicates' types. Doing the same thing by hand is probably my number two recommendation of how not to code in Prolog. Number one is "the dynamic database is evil", but does anyone listen to me? Never.

Edit 2: Covington et al's Coding Guidelines for Prolog make the same point:

  5.13 Develop your own ad hoc run-time type and mode checking system.

  Many problems during development (especially if the program is large and/or there
  are several developers involved) are caused by passing incorrect arguments. Even
  if the documentation is there to explain, for each predicate, which arguments are
  expected on entry and on successful exit, they can be, and all too often they are,
  overlooked or ignored. Moreover, when a “wrong” argument is passed, erratic be-
  havior can manifest itself far from where the mistake was made (and of course,
  following Murphy’s laws, at the most inconvenient time).

  In order to significantly mitigate such problems, do take the time to write your
  own predicates for checking the legality of arguments on entry to and on exit from
  your procedures. In the production version, the goals you added for these checks
  can be compiled away using goal_expansion/2.
https://arxiv.org/abs/0911.2899

>> I could linearize the arguments and include them in the body but this destroys the indexing and can put me into "defaulty representation" territory.

Sorry, I don't know what either of those are: "linearize the arguments" and "defaulty representation".

Prolog only has first-argument indexing normally, although some implementations let you change that and use your own indexing scheme. Is that what you did?

Re: Can logic programming be liberated from predicates and backtracking? [pdf]

#58
post #41

Earlier quoted context omitted.

It isn't. I do most of my programming in Prolog, I write oodles of it daily, and it's not a problem. You learn to think that way easily. The argument is basically that Prolog is not 100% declarative and that if we jump through a few hoops, and translate it all to functional notation, we can make it "more declarative". But let's instead compare the incomplete declarativeness of Prolog to a fully-imperative, zero-decla…

Serious question, how do you deal with typos in functors? And is your techniques specific to the implementation of Prolog you use? Recently I had a maddening experience chasing this down: result(World0, move(robot(R), Dir), World) :- dissoc(World0, at(robot(R), X0), World1), direction_modifier(Dir, Modifier), X #= X0+Modifier, conj(World1, at(robot(R), X), World). result(World0, drop_rock(robot(R), Place), World) :-…

so so so so so so so so so much this. I have tried to make prolog a part of various systems on and off for two decades and the ergonomics and basic practical shit like this is why it never works.

the answer is always: do a lot of manual stuff that the language should do for you. I can, but I can't get a team to.

Re: Can logic programming be liberated from predicates and backtracking? [pdf]

#59
post #41

Earlier quoted context omitted.

Serious question, how do you deal with typos in functors? And is your techniques specific to the implementation of Prolog you use? Recently I had a maddening experience chasing this down: result(World0, move(robot(R), Dir), World) :- dissoc(World0, at(robot(R), X0), World1), direction_modifier(Dir, Modifier), X #= X0+Modifier, conj(World1, at(robot(R), X), World). result(World0, drop_rock(robot(R), Place), World) :-…

so so so so so so so so so much this. I have tried to make prolog a part of various systems on and off for two decades and the ergonomics and basic practical shit like this is why it never works. the answer is always: do a lot of manual stuff that the language should do for you. I can, but I can't get a team to.

Then don't use Prolog. It's not mandatory.

For the record I never have problems like that and I'm sure I'm not special. Well, not in that way. This all comes under the heading of "learn what works". You have to do that with any language.

Edit: as a slightly less flippant answer (sorry) Prolog doesn't "do a lot of manual stuff that the language should do for you" because the Prolog community doesn't think the language should do those things for you and I agree. Take for instance inheritance and composition, like in object orientation. There's no reason Prolog should do that for you. If it did, it would shoehorn you into a certain programming paradigm that can feel like a straightjacket when you don't need it, but you absolutely need to use it because that's what the "language does for you". Prolog instead gives you the tools to do all the things you need, when you need them. It's more work, for sure, but it's also more freedom. I spent most of my career in the industry working with very rigidly OOP languages and that's one reason why I escaped into academia, where I can program in Prolog (see what I did there?) all day without having to declare a class property if I don't want to. And if I really wanted to, I could go all the way and write something like Logtalk:

https://logtalk.org/

Another example of something that Prolog doesn't do for you, and that you don't always need, but can always do yourself if you need it, is typing; like I point out in the sibling comment. Why should Prolog do that for you? Are we going to have the whole argument about strongly typed vs. weakly typed languages all over again? I think not. If you want types in Prolog, you can roll your own. Now try to write, say, C# code without types, when you really don't need the bother.

Re: Can logic programming be liberated from predicates and backtracking? [pdf]

#60

Earlier quoted context omitted.

Really interesting to hear! I was quite hooked to Prolog in a previous life. Then the limiting factor was the tooling, for really practical use. Could you tell a bit about your Prolog environment?

seconded

I use the SWI-Prolog IDE:

https://www.swi-prolog.org/PceEmacs.html

I suppose it is a bit spartan, but it has a ton of functionality that I find indispensable [1]. For example, when I place my cursor on a variable in the editor it highlights all the variables that unify with it in the same clause, and it will highlight singleton variables in a different colour so you can catch errors caused by typos easily. It is also aware of things like imported predicates, undefined or dynamic predicates, multi-file predicates etc, and will highlight them accordingly. It has some (limited) auto-complete and code-expansion etc. and a status line that gives you very good information about the kind of term you have your cursor on - where it's defined if it's a predicate, its name and arity and how many clauses etc, basically much of the information you can get from querying the program database with various program inspection built-ins. Some of my colleagues use VS Code to write Prolog instead and I keep shaking my head and grumbling about the errors they keep making that they wouldn't if they used the SWI-Prolog IDE instead. Kids, these days. In my youth, we wrote all our Prolog on Notepad! And compiled on Dos!

(nope. never)

SWI also has a graphical debugger, which however I never use:

https://www.swi-prolog.org/pldoc/doc/_SWI_/xpce/prolog/lib/g...

I know some people swear by its name but I prefer the textual debugger. Again this one looks a little spartan :)

More goodies in SWI: cross-referencer:

https://www.swi-prolog.org/gxref.md

And profiler:

  1 ?- profile(between(1,10,_)).
  =====================================================================
  Total time: 0.000 seconds
  =====================================================================
  Predicate                       Box Entries =    Calls+Redos     Time
  =====================================================================
  between/3                                 1 =        1+0         0.0%
  true.

And lots and tons of facilities for debugging and error handling, unit testing, all sorts of libraries, a package manager etc.

________________________

[1] You can customise the IDE colours too. There's a dark theme:

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

There's some screenshots here:

https://swi-prolog.discourse.group/t/questions-about-ide-the...

Post reply on HN