# Alternative to SSU

**URL:** <https://swi-prolog.discourse.group/t/alternative-to-ssu/6702>\
**Category:** General\
**Created:** [July 11, 2023, 9:23pm UTC](https://swi-prolog.discourse.group/t/alternative-to-ssu/6702 "2023-07-11T21:23:54Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![z5h](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/z5h/32/5445_2.png) [@z5h](https://swi-prolog.discourse.group/u/z5h)\
**Post date:** [July 11, 2023, 9:23pm UTC](https://swi-prolog.discourse.group/t/alternative-to-ssu/6702/1 "2023-07-11T21:23:54Z")

</div>

If I understand correctly, SSU syntax is borrowed from another language, and not (easily?) portable across Prologs.

And let’s consider this example for a moment:

```prolog
ab_status(A,B,Status) :- 
	A, B, Status = both(A,B).

ab_status(A,B,Status) :- 
	A, \+B, Status = just_a(A).

ab_status(A,B,Status) :-
	\+A, B, Status = just_b(B).

ab_status(A,B,Status) :-
	\+A, \+B, Status = neither.

```

Rewriting the above using SSU wouldn’t omit the cost or repeated evaluations of A and B.

On the other hand, if we adhere to a consistent style of guards, we could refactor the above with a sort of “ssu indicator”  
`:- ssu(ab_status ...)`

This would refactor `ab_status` to something like:

```prolog
ab_status(A,B,S) :-
(A -> true; NotA = true), ...,
(A, B, S=both) ;
(A, NotB, S=just_a) ;
(NotA, B, S=just_b(B)) ;
(NotA, \+NotB, S=neither)

```

This would be some (portable) rewriting for optimization. But it relies on convention and silently fails to optimize if the convention is not adhered to. Could one defend against creating an incorrect rewrite?

Does this seem at all fruitful or totally misguided?

---

<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:** [July 11, 2023, 10:09pm UTC](https://swi-prolog.discourse.group/t/alternative-to-ssu/6702/2 "2023-07-11T22:09:42Z")

</div>

Sounds like we could just use:

```prolog
goal_t(Goal, T) :-
    ( call(Goal)
    -> T = true
    ; T = false
    ).
    
ab_status(A, B, Status) :-
    goal_t(A, AT),
    goal_t(B, BT),
    atom_concat(AT, BT, ABT),
    ab_status_(ABT, A, B, Status).
    
ab_status_(truetrue, A, B, both(A, B)).
ab_status_(truefalse, A, _B, just_a(A)).
ab_status_(falsetrue, _A, B, just_b(B)).
ab_status_(falsefalse, _A, _B, neither).

```

This avoids choicepoints with e.g.:

```prolog
?- ab_status(true, true, S).
S = both(true, true).

?- ab_status(true, false, S).
S = just_a(true).

?- ab_status(false, false, S).
S = neither.

?- ab_status(false, true, S).
S = just_b(true).

```

---

<div class="post-metadata">

**Author:** ![peter.ludemann](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/peter.ludemann/32/48_2.png) [@peter.ludemann](https://swi-prolog.discourse.group/u/peter.ludemann)\
**Post date:** [July 11, 2023, 10:31pm UTC](https://swi-prolog.discourse.group/t/alternative-to-ssu/6702/4 "2023-07-11T22:31:27Z")

</div>

The semantics of `=>` are a bit strange if unification happens in a guard in the head. For example, in the following, `p/1`, `q/1`, and `r/1` should all mean the same:

```prolog
p(X), eq(X,1) => true.
p(_) => fail.

q(X), X=1 => true.
q(_) => fail.

r(1) => true.
r(_) => fail.

eq(X, Y) :- X=Y. % or: eq(X, X).

```

However, `p(X)` succeeds (with `X=1`) but `q(X)` and `r(X)` quietly fail.  
(The definition of `p/1` using `eq/2` breaks the SSU semantics that no unification occurs in the head.)

So, any conversion from SSU to non-SSU neds to change unification to subsumes\_term/2 or similar.

---

<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:** [July 12, 2023, 6:22am UTC](https://swi-prolog.discourse.group/t/alternative-to-ssu/6702/5 "2023-07-12T06:22:38Z")

</div>

> [@z5h](#):
>
> If I understand correctly, SSU syntax is borrowed from another language, and not (easily?) portable across Prologs.

It is not terribly hard to port to any Prolog system that provides term\_expansion/2. It means you must modify arguments holding non-variables in the head into a variable and use `==/2` and similar to verify the shape of the argument without binding it. Also multiple occurrences of the same variable in the head must use subsumes\_term/2. Next you add the guards, a !/0 call and the body. Finally you add a catch all clause that raises an exception if no rules reached the body.

It is less complicated in the VM. That basically adds code to verify no trailing happened in the current implementation. The alternative would be to have specializations of the unify instructions that fail rather than trail or have some mode to prevent trailing during the head unification. Not sure that is worth the trouble.
