I’m trying to build a network analyzer that uses SWI-Prolog as knowledge base.
I’m creating a predicate whose purpose is to check if a network is already present in the KB, otherwise it must perform other operation before adding it:
This means that host 192.168.0.1 is connected to 192.168.0.0/24 and has two interfaces, one of them connects him to a new network. And host 192.168.2.1 is connected to 192.168.2.0/24.
So the goal of the predicate is to do some operation only on 192.168.1.0/24.
The problem: during backtracking over networks, the result of this predicate is always the result of the last network tested (in this example 192.168.2.0 that makes the predicate return false).
Is there a way to make this predicate always return true even if didn’t find any new networks ?
Since, as the documentation for ->/2 states " Please note that (If -> Then) acts as (If -> Then ; fail), making the construct fail if the condition fails."
Adding a true branch doesn’t work because backtracking would stop because the predicate is returning true after 192.168.0.0, which already exists in KB.
(\+)/1 can be tricky to get right if all the arguments aren’t ground. In your case, you seem to have two uninstantiated variables, Subnet and the anonymous _. Presumably you’re planning to use Subnet later in the predicate (otherwise you’d be getting a warning about Subnet being a singleton variable)? - but the (\+)/1 will undo any bindings, so the use of “not” seems wrong.
I’ll try to make it more clear:
I need something that emulates the iteration through the arguments 192.168.0.0, 192.168.1.0 and 192.168.2.0.
For each one, checks if already exists and otherwise will perform some operation.
Finally, I need it to return always true.
I try to avoid dynamic predicates – in this case, I might keep the information in an associative list (e.g., using dicts or red-black trees) – this maintains the declarative nature of the program.
An exception is if I’m loading some data and need to do additional processing on the data to get it into a suitable form. In that situation, I usually break my program into two parts – the first part processes the data and produces a new set of facts that can be used as-is, and the second part uses the generated data.
I can’t answer your question because I don’t understand your intent. Your code seems to be wrong because Subnet is uninstantiated when you call \\+ network(Network, Subnet, _) and it won’t become instantiated to a value in that situations (it’s essentially equivalent to \\+ network(Network _, _)).
So, it finds (implied) non existent Network(s) for Host and then executes writeln (as a substitute for operation(…), maybe assertz for instance).
Second version assumes that operation() is side effects only.
Both will apply operation() to all implied non existent networks.
Use once(add_network(…)) to do just first.