DEV Community

Gilbert for The Clause

Posted on • Edited on

A Nicer if-then-else Syntax in Prolog

Prolog has an amazing syntax, thanks to it both being homoiconic and supporting custom operators. However, writing conditionals in Prolog is often a drag.

Fortunately, we don't have to convince or wait for Prolog implementations to implement a nicer syntax. Instead, we can create our own if-else syntax today!

Example Usage

%%
%% Before
%%
foo(X) :-
  (
    X > 50 ->
    Y is X * 2,
    bar(X, blah)
  ; baz(10, 20)
  ),
  last(X).

%%
%% After
%%
foo(X) :-
  if (X > 50) then (
    Y is X * 2,
    bar(X, blah)
  )
  else (
    baz(10, 20)
  ),
  last(X).

%%
%% Before
%%
shorter_foo(X) :- (X > 10 -> bar(X); baz(X)).

%%
%% After
%%
shorter_foo(X) :- if X > 10 then bar(X) else baz(X).
Enter fullscreen mode Exit fullscreen mode

Example Usage (or operator)

I also threw in a bonus or operator so you can do "or" logic without introducing additional choice points, and not have to worry about catching multiple terms (due to it having a stronger precedence than the comma , operator):

%%
%% Before
%%
multi_foo(X, Y) :- (foo(X), !; bar(Y)).

%%
%% After
%%
multi_foo(X) :- foo(X) or bar(Y).

%%
%% Before
%%
multi_foo(X, Y) :-
  ((foo(X), !; bar(X)) ->
    Y = true
  ; Y = false
  ).

%%
%% After
%%
multi_foo(X) :-
  if (foo(X) or bar(X)) then (
    Y = true
  )
  else (
    Y = false
  ).
Enter fullscreen mode Exit fullscreen mode

The Code

Here's the code you can copy/paste into your own project to make use of this sweet, sweet syntax.

There may even be a better way using term_expansion. If you find one, leave it in the comments!

:- op(990, fx, if).
:- op(985, yfx, then).
:- op(985, yfx, else).
:- op(985, yfx, elseif).
:- op(800, xfx, or).

if(X) :- (if_then(X, Then) -> call(Then); true).

if_then(then(elseif(Try, Cond), MaybeThen), Then) :-
  !,
  (if_then(Try, Then) -> true; call(Cond), Then = MaybeThen).

if_then(then(Cond, Then), Then)  :-
  !,
  call(Cond).

if_then(else(Try, MaybeThen), Then) :-
  !,
  (if_then(Try, Then) -> true; Then = MaybeThen).

or(X,Y) :- call(X) -> true; call(Y).
Enter fullscreen mode Exit fullscreen mode

Top comments (0)