# Would it be possible to implement a second SSU Operator "\*=\>" which allows for backtracking in the left hand side?

**URL:** <https://swi-prolog.discourse.group/t/would-it-be-possible-to-implement-a-second-ssu-operator-which-allows-for-backtracking-in-the-left-hand-side/9223>\
**Category:** Help!\
**Created:** [August 21, 2025, 1:50pm UTC](https://swi-prolog.discourse.group/t/would-it-be-possible-to-implement-a-second-ssu-operator-which-allows-for-backtracking-in-the-left-hand-side/9223 "2025-08-21T13:50:51Z")\
**Posts on this page:** 17\
**Page:** 1

<div class="post-metadata">

**Author:** ![Frank\_Schwidom](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/frank_schwidom/32/7662_2.png) [@Frank\_Schwidom](https://swi-prolog.discourse.group/u/Frank_Schwidom)\
**Post date:** [August 21, 2025, 1:50pm UTC](https://swi-prolog.discourse.group/t/would-it-be-possible-to-implement-a-second-ssu-operator-which-allows-for-backtracking-in-the-left-hand-side/9223/1 "2025-08-21T13:50:51Z")

</div>

Currently I have to write

> p008(X), (var(X) ; between( 0, 5, X)) =\> between( 0, 5, X) .

but I would like to write:

> p008(X), between( 0, 5, X) \*=\> true.

I find the SSU operator ‘=\>’ very useful. Is this actually a thing in logtalk?

Regards,  
Frank Schwidom

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [August 21, 2025, 2:30pm UTC](https://swi-prolog.discourse.group/t/would-it-be-possible-to-implement-a-second-ssu-operator-which-allows-for-backtracking-in-the-left-hand-side/9223/2 "2025-08-21T14:30:53Z")

</div>

> [@Frank\_Schwidom](#):
>
> p008(X), between( 0, 5, X) \*=\> true.

Picat, from which `=>` comes, has `*=>`, but I think it implies that subsequent clauses are still considered. That you seem to want is something that commits to the clause, but maintains non-determinism of the guard?

That said, I’d write

```
p008(X), var(X) => between(0,5,X).
p008(X) => between(0,5,X).

```

Depending on the other clauses as the above is simply

```
p008(X) :- between(0,5,X).

```

The overall idea behind =\> is to provide a deterministic switch that is not subject to steadfastness issues.

---

<div class="post-metadata">

**Author:** ![Frank\_Schwidom](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/frank_schwidom/32/7662_2.png) [@Frank\_Schwidom](https://swi-prolog.discourse.group/u/Frank_Schwidom)\
**Post date:** [August 21, 2025, 2:38pm UTC](https://swi-prolog.discourse.group/t/would-it-be-possible-to-implement-a-second-ssu-operator-which-allows-for-backtracking-in-the-left-hand-side/9223/3 "2025-08-21T14:38:39Z")

</div>

In my examples p008(6) would fail with an error.

> ?- p008( 6).  
> ERROR: No rule matches p008(6)  
> ERROR: In:  
> ERROR: [12] p008(6)  
> ERROR: [11] toplevel\_call(user:user: …) at /usr/local/lib/swipl/boot/toplevel.pl:1319

This is not the case in your examples.

> (ins)?- p008( 6).  
> false.

This is not what I want to get.

---

<div class="post-metadata">

**Author:** ![Frank\_Schwidom](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/frank_schwidom/32/7662_2.png) [@Frank\_Schwidom](https://swi-prolog.discourse.group/u/Frank_Schwidom)\
**Post date:** [August 21, 2025, 2:44pm UTC](https://swi-prolog.discourse.group/t/would-it-be-possible-to-implement-a-second-ssu-operator-which-allows-for-backtracking-in-the-left-hand-side/9223/4 "2025-08-21T14:44:23Z")

</div>

> [@jan](#):
>
> Picat, from which `=>` comes, has `*=>`, but I think it implies that subsequent clauses are still considered. That you seem to want is something that commits to the clause, but maintains non-determinism of the guard?

In case we want to implement it I can also live with another operator symbol.

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [August 21, 2025, 2:53pm UTC](https://swi-prolog.discourse.group/t/would-it-be-possible-to-implement-a-second-ssu-operator-which-allows-for-backtracking-in-the-left-hand-side/9223/5 "2025-08-21T14:53:40Z")

</div>

> [@Frank\_Schwidom](#):
>
> In case we want to implement it I can also live with another operator symbol.

Actually the Picat is `?=>` I think. The more principled question is whether or not we want non-determinism in the guard. It feels counter intuitive to me. Opinions? Existing current practice in similar systems?

---

<div class="post-metadata">

**Author:** ![brebs](https://avatars.discourse-cdn.com/v4/letter/b/e9c0ed/32.png) [@brebs](https://swi-prolog.discourse.group/u/brebs)\
**Post date:** [August 21, 2025, 3:46pm UTC](https://swi-prolog.discourse.group/t/would-it-be-possible-to-implement-a-second-ssu-operator-which-allows-for-backtracking-in-the-left-hand-side/9223/6 "2025-08-21T15:46:46Z")

</div>

> [@Frank\_Schwidom](#):
>
> ?- p008( 6).  
> false.

Could just use a standard predicate i.e. `:-`, with !/0 where appropriate (and maybe even throw/1), to have all the desired flexibility.

Personally, I never use [SSU](https://www.swi-prolog.org/pldoc/man?section=ssu).

---

<div class="post-metadata">

**Author:** ![Frank\_Schwidom](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/frank_schwidom/32/7662_2.png) [@Frank\_Schwidom](https://swi-prolog.discourse.group/u/Frank_Schwidom)\
**Post date:** [August 21, 2025, 9:06pm UTC](https://swi-prolog.discourse.group/t/would-it-be-possible-to-implement-a-second-ssu-operator-which-allows-for-backtracking-in-the-left-hand-side/9223/7 "2025-08-21T21:06:28Z")

</div>

OK, since it’s clear that not everyone is immediately convinced by the idea of the `*=>` operator, let me do a bit of promotion for it.

First, I find the `=>` operator already quite compelling because it places a type check at the start of a predicate, which is very straightforward to write since I don’t need to use the `must_be` notation. Additionally, it allows me to easily extend the scope of a predicate by simply adding more rules.

Of course, the `:-` operator could achieve similar results if you accept a logical `false` instead of an error, but this often leads to silent and hard-to-debug failures.

From a software development perspective, I personally prefer receiving a hard error when my domain boundaries are clearly violated, rather than dealing with a silent failure that’s tricky to track down.

Moreover, the `=>` operator makes it possible to create new predicates by combining existing ones, as illustrated in the following example:

```prolog
p001(I, O), var(I) => O = var.

p002(I, O), nonvar(I) => O = nonvar.

catchmatch(GOAL) :- catch(GOAL, error(existence_error(matching_rule, _), _), false).

p003(I, O), catchmatch(p001(I, O)) => true.
p003(I, O), catchmatch(p002(I, O)) => true.

```

Now, imagine that the predicates `p001` and `p002` can produce multiple results. The `*=>` operator in rule `p003` could simplify things significantly: you get all the results from `p001` and `p002` without extra effort, while still actively enforcing domain constraints.

```prolog
p003(I, O), catchmatch(p001(I, O)) *=> true.
p003(I, O), catchmatch(p002(I, O)) *=> true.

```

Frank Schwidom

---

<div class="post-metadata">

**Author:** ![Frank\_Schwidom](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/frank_schwidom/32/7662_2.png) [@Frank\_Schwidom](https://swi-prolog.discourse.group/u/Frank_Schwidom)\
**Post date:** [August 21, 2025, 9:32pm UTC](https://swi-prolog.discourse.group/t/would-it-be-possible-to-implement-a-second-ssu-operator-which-allows-for-backtracking-in-the-left-hand-side/9223/8 "2025-08-21T21:32:05Z")

</div>

But a problem keeps remaining. What if I have a legit false from for instance p001 (from the body) it is then interpreted as a domain violation in p003. Maybe I’m wrong with my idea. Lets sleep 1 night about that.

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [August 22, 2025, 6:40am UTC](https://swi-prolog.discourse.group/t/would-it-be-possible-to-implement-a-second-ssu-operator-which-allows-for-backtracking-in-the-left-hand-side/9223/9 "2025-08-22T06:40:18Z")

</div>

> [@Frank\_Schwidom](#):
>
> Lets sleep 1 night about that.

Good plan 🙂 I’m mostly interested in what others think about this. Note that, AFAIK, CHR (another committed-choice language) does not allow for non-determinism in the guard. Also, you consider the rules “type (domain) checked”. That is a reasonable view, but non-determinism and (type) checking are in different parts of my brain 🙂

---

<div class="post-metadata">

**Author:** ![Boris](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/boris/32/7486_2.png) [@Boris](https://swi-prolog.discourse.group/u/Boris)\
**Post date:** [August 22, 2025, 9:03am UTC](https://swi-prolog.discourse.group/t/would-it-be-possible-to-implement-a-second-ssu-operator-which-allows-for-backtracking-in-the-left-hand-side/9223/10 "2025-08-22T09:03:22Z")

</div>

Here is my opinion (I think this has come up before).

For the current SSU operator, the guard must have the “@” mode for variables shared with the head; that is:

> Argument will not be further instantiated than it is at call-time.

I know this is a very stringent requirement. Some of it probably can’t be checked at compile time, for example:

```prolog
foo(A, B), between(1, 3, A) => B is 0 - A.

```

Currently, this works (or throws) with a nonvar A; but it also just works with a free variable in A. But surely it looks like a programming error?

At least for me, if `=>` worked like this, it is easier to comprehend the meaning of relaxing the requirement for the guard.

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [August 22, 2025, 9:30am UTC](https://swi-prolog.discourse.group/t/would-it-be-possible-to-implement-a-second-ssu-operator-which-allows-for-backtracking-in-the-left-hand-side/9223/11 "2025-08-22T09:30:34Z")

</div>

> [@Boris](#):
>
> For the current SSU operator, the guard must have the “@” mode for variables shared with the head

That is how I intended it and it is a requirement to guarantee steadfastness. Unfortunately I see no reasonable way to enforce that, so -as is- the guard is just a arbitrary Prolog goal …

I guess the question arises whether we should embrace arbitrary goals or stick with the original intend and consider guards that bind the goal arguments “bad”? I must admit that I (mis)use the guard occasionally.

I think there are four key properties to SSU:

- Simplify pattern matching on arguments that may contain variables.
- Guarantee steadfastness.
- Get an error if no rule matches.
- Encourage clean usage of commits (cuts).

Allow arbitrary guards destroys the second, harms the 4th and preserves the other two properties.

---

<div class="post-metadata">

**Author:** ![kwon-young](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/kwon-young/32/4841_2.png) [@kwon-young](https://swi-prolog.discourse.group/u/kwon-young)\
**Post date:** [August 24, 2025, 7:57pm UTC](https://swi-prolog.discourse.group/t/would-it-be-possible-to-implement-a-second-ssu-operator-which-allows-for-backtracking-in-the-left-hand-side/9223/13 "2025-08-24T19:57:31Z")

</div>

Hello,  
Here is just another data point for this discussion.

I have recently managed to get SSU click in my head and use it extensively, e.g. for parsing terms or expressions.  
The one thing I rely on very strongly is the guaranteed steadfastness (nothing will be bind in the head or guard).

> [@Frank\_Schwidom](#):
>
> First, I find the `=>` operator already quite compelling because it places a type check at the start of a predicate

In my opinion, relying on the generic error from SSU is not a good way to do type checking.  
It works but is not the “correct” solution.

My own take on your first example:

```prolog
p008(X) :-
  ( between(0, 5, X)
  -> true
  ; domain_error(X, between(0, 5))
  ).

```

I know it is more verbose, but worth it in my opinion.

---

<div class="post-metadata">

**Author:** ![Frank\_Schwidom](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/frank_schwidom/32/7662_2.png) [@Frank\_Schwidom](https://swi-prolog.discourse.group/u/Frank_Schwidom)\
**Post date:** [August 24, 2025, 9:09pm UTC](https://swi-prolog.discourse.group/t/would-it-be-possible-to-implement-a-second-ssu-operator-which-allows-for-backtracking-in-the-left-hand-side/9223/14 "2025-08-24T21:09:59Z")

</div>

> [@kwon-young](#):
>
> The one thing I rely on very strongly is the guaranteed steadfastness (nothing will be bind in the head or guard).

But this is not the case in the current implementation. This example:

> p007(X), between( 0, 5, X) =\> between( 0, 5, X) .

gives me the following result:

> ?- p007(X).  
> X = 0.

and this:

> p005(X), between( 0, 5, X) =\> true.

the same:

> ?- p005( X).  
> X = 0.

So the guard binds values and hinders recursion in the LHS. Maybe it is the same in picat, I didn’t check that.

---

<div class="post-metadata">

**Author:** ![kwon-young](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/kwon-young/32/4841_2.png) [@kwon-young](https://swi-prolog.discourse.group/u/kwon-young)\
**Post date:** [August 24, 2025, 9:20pm UTC](https://swi-prolog.discourse.group/t/would-it-be-possible-to-implement-a-second-ssu-operator-which-allows-for-backtracking-in-the-left-hand-side/9223/15 "2025-08-24T21:20:22Z")

</div>

> [@Frank\_Schwidom](#):
>
> But this is not the case in the current implementation.

Isn’t this just a ~~“pending”~~ known bug of the current implementation ?  
The [documentation](https://www.swi-prolog.org/pldoc/man?section=ssu-guard) says, this is just a quirk of the implementation and you should not do it:

> Though not enforced, guard code shall not instantiate variables in the Head because this breaks the promise of SSU and may make the node non-steadfast.

In my case, I forgot about this in order to retain steadfastness (which is important to me).

– edits–  
There is even a little note in the implementation explaining that the guard is not checked because of thechnical difficulties

---

<div class="post-metadata">

**Author:** ![Frank\_Schwidom](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/frank_schwidom/32/7662_2.png) [@Frank\_Schwidom](https://swi-prolog.discourse.group/u/Frank_Schwidom)\
**Post date:** [August 24, 2025, 9:43pm UTC](https://swi-prolog.discourse.group/t/would-it-be-possible-to-implement-a-second-ssu-operator-which-allows-for-backtracking-in-the-left-hand-side/9223/16 "2025-08-24T21:43:21Z")

</div>

> [@kwon-young](#):
>
> Isn’t this just a “pending” bug of the current implementation ?

Sorry, with “current implementation” I meant my installation. I have currently

> Welcome to SWI-Prolog (threaded, 64 bits, version 9.3.20-DIRTY)

installed. Maybe it behaves different in later versions.

---

<div class="post-metadata">

**Author:** ![Frank\_Schwidom](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/frank_schwidom/32/7662_2.png) [@Frank\_Schwidom](https://swi-prolog.discourse.group/u/Frank_Schwidom)\
**Post date:** [August 24, 2025, 9:54pm UTC](https://swi-prolog.discourse.group/t/would-it-be-possible-to-implement-a-second-ssu-operator-which-allows-for-backtracking-in-the-left-hand-side/9223/17 "2025-08-24T21:54:26Z")

</div>

> [@kwon-young](#):
>
> just a quirk of the implementation

I got it - it has nothing to do with the version. So I should write instead of p005 and p007:

> p00B(X), \+ \+ between( 0, 5, X) =\> between( 0, 5, X).

Then I get:

> (ins)?- p00B(6).  
> ERROR: No rule matches p00B(6)  
> ERROR: In:  
> ERROR: [12] p00B(6)  
> ERROR: [11] toplevel\_call(user:user: …) at /usr/local/lib/swipl/boot/toplevel.pl:1319  
> (ins)?- p00B(3).  
> true.
> 
> (ins)?- p00B(X).  
> X = 0 ;  
> X = 1 ;  
> X = 2 ;  
> X = 3 ;  
> X = 4 ;  
> X = 5.

---

<div class="post-metadata">

**Author:** ![kwon-young](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/kwon-young/32/4841_2.png) [@kwon-young](https://swi-prolog.discourse.group/u/kwon-young)\
**Post date:** [August 24, 2025, 9:59pm UTC](https://swi-prolog.discourse.group/t/would-it-be-possible-to-implement-a-second-ssu-operator-which-allows-for-backtracking-in-the-left-hand-side/9223/18 "2025-08-24T21:59:45Z")

</div>

> [@Frank\_Schwidom](#):
>
> p00B(X), \+ \+ between( 0, 5, X) =\> between( 0, 5, X).

double negation is a nice trick, but expensive.  
Another solution is testing explicitly what you want:

```prolog
p00B(X), (var(X) ; 0 =< X, X =< 5) => between(0, 5, X).

```

If the guard become too long or heavy, you can always refactor into another predicate.  
–edit–  
Just a little thought here: using SSU (and achieving steadfastness) is the process of separating that small imperative portion of your code from the general “messy” pure non-deterministic prolog code ^^
