1

I'm having trouble with a personal Prolog exercise. For context, the idea is to make a little digital logic tool which makes cell instances and pin connections. The hope is to let the program manage pin connection details, while the user can say, hey, connect these two instances together.

I don't how how to add a constraint which says that a pin connection shouldn't be made if the pin is already connected. My program goes into an infinite loop.

I also don't know if my approach is sane. Is there a better way to approach this problem in Prolog? Is Prolog just not cut out for my task? I am considering using assertz to create dynamic rules, but that seems to be more trouble, but maybe it's a smart way to go? I don't know.

What's going on:

connect(...) is the command to specify the what instances should be connected. They are being connected by instance name. And, connected(...) should be the result. So,

connected(...) :- connect(...) , other constraints, not(has_driver(...)). 

The trouble comes in because has_driver(...) looks at all the connected(...) items that already exist with bound variables. This is where a loop potentially happens. Surely I'm conceptually off here with the recursion. I need to make a stop case, but what would that possibly look like?

Strangely, the rule file seems to load without issue, but I get an infinite loop when I run the query: connected(SN, DN, SP, DP).

Here is my rule file so far....

type(pin_function, pf_bit). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Little cell library %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% FLOP type(cell, c_flop). cell_has_pin_func_src(c_flop, q , pf_bit). cell_has_pin_func_dst(c_flop, d , pf_bit). cell_has_pin_func_dst(c_flop, clk, pf_clk). cell_has_pin_func_dst(c_flop, rst, pf_rst). %%% NAND GATE type(cell, c_nand2). cell_has_pin_func_src(c_nand2, q, pf_bit). cell_has_pin_func_dst(c_nand2, a, pf_bit). cell_has_pin_func_dst(c_nand2, b, pf_bit). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Try to make a connection %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% instance(Name) :- instantiate(Cell, Name), type(cell, Cell). inst_is_type(Name, Type) :- instance(Name), instantiate(Cell, Name), type(Cell, Type). has_driver(DN, DP) :- connected( _, DN, _, DP). has_load(SN, SP) :- connected(SN, _, SP, _). connected(SN, DN, SP, DP) :- connect(SN, DN, Pin_Func), % Source, Dest, pin function instantiate(Src_C, SN), instantiate(Dst_C, DN), cell_has_pin_func_src(Src_C, SP, Pin_Func), cell_has_pin_func_dst(Dst_C, DP, Pin_Func). %not(has_driver(DN, DP)). % <<<<------Uncomment this line for trouble has_driver(DN, DP) :- connected( _, DN, _, DP). has_load(SN, SP) :- connected(SN, _, SP, _). %%%Try a little digital design instantiate(c_flop, ff1). instantiate(c_flop, ff2). connect(ff2, ff1, pf_bit). connect(ff1, ff2, pf_bit). 
2
  • The problem here is you've got 2 connections, and then has_driver wants to prevent them from being accepted... in an infinite loop. I think the way forward would be to rewrite has_driver so it doesn't call connected, then introduce a list of connections rather than just 2. Commented Jul 13 at 18:08
  • The predicates has_driver(DN, DP) and has_load(SN, SP) are in twice (not that removing the duplicates solves the infinite-loop problem). Its best to follow swi-prolog's load-time warning to keep predicates together, to spot such mistakes easier. Commented Jul 14 at 20:26

1 Answer 1

0

If I understand your intention correctly, the predicate connect/3 is intended to change the state of the system - things that have not been connected before are now connected. As pure, declarative logic programming is stateless, there are two canonical options for going about this:

  1. Leave the declarative fragment of Prolog and have connect/3 assert the predicate connected/4;

  2. thread the current state as an additional argument.

The first option is simpler in that it does not require any additional data structures (such as lists) for representing the current state. However, it does mean that your program is no longer truly declarative, as the current state depends on the connect/3 predicates called in the past. Hence, some Prolog programming guides strongly discourage explicitly asserting and retracting predicates to the so-called "dynamic database" (my personal view is more differentiated, and I do use the dynamic database in my daily programming practice). If you adopt this approach, you can leave the testing logic as is, since has_driver(DN, DP) would now call connected/4, but since this predicate is not defined in code but asserted by connect/3 there is no more unwanted recursion.

The second option would capture the connections as, say, a list of terms of the form connected(SN, DN, SP, DP). Then, connect could take 5 arguments, connect(SN,DN,Pin_Func,OldConnections,NewConnections) and would represent a function mapping OldConnections to NewConnections. The definition of connect/5 could then check whether an entry is already in OldConnections before adding it to NewConnections. In this design, connected/4 is no longer a dedicated predicate at all.

You could see Option 1 as closer to using a (deductive) database system, and Option 2 as closer to the way you would solve this problem in a pure functional language. I personally think both have their merits, and in my opinion the fact that Prolog can naturally be used either way is one of its strengths. If this were a subproblem in larger architecture, then that would determine which route to go down; if this is merely a stand-alone problem to help you get your head around Prolog, I think it would be very instructive to implement both and appreciate the differences.

Sign up to request clarification or add additional context in comments.

5 Comments

Prolog indeed is an underappreciated imperative programming language. :)
Is it obvious to anyone else that this was written by an AI bot?
@brebs I am not sure whether one should reply to a comment using another comment, but I can assure you that I have not used any generative AI support whatsoever in formulating this answer.
Now I have to prove I'm not a bot!
no, it is not obvious to me at all. the thought did not even enter my mind.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.