[m-users.] Impurity needed?

Zoltan Somogyi zoltan.somogyi at runbox.com
Tue Feb 14 01:05:30 AEDT 2023


2023-02-13 22:46 GMT+11:00 "Volker Wysk" <post at volker-wysk.de>:
> I've read the chapter on trace goals in the language reference manual. They
> don't seem to fit my needs. The trace goal can't bind any variables in the
> surrounding code. It also isn't allowed to use a mutable variable to pass
> information from inside the trace goal to outside of it.
>
> And, I've always wondered, don't trace goals break purity?

As the name suggests, trace goals are intended to help with debugging.
Any language feature that allows a predicate to generate debugging output
without having a di/uo pair of I/O state arguments necessarily breaks purity.
The point of the restrictions to mention above is to separate the code inside
the trace goal scope from the code around it, which is the code being debugged.
If the trace goal bound variables that the code outside the trace goal scope
could read, then you couldn't just disable the trace goal once you have finished
debugging, e.g. by switching off the --trace-flag that the trace scope's compile-time
condition required. A trace goal that is disabled either by its compile-time or
its runtime condition is never executed, and in that disabled state, it does not break
purity.

>From the compiler-writer's point of view (i.e. my view :-), trace goals have
some but not all properties of impure code. For example, like impure Mercury code,
the compiler must generate target language code for the code inside the trace scope
even though the rest of the predicate body does not use any of its outputs
(since it has none). On the other hand, while the compiler must generate code
to execute a call to an impure predicate even if has no (unignored) outputs, it does *not*
need to generate code to pure predicate that has no unignored outputs, even
if it contains trace goals.

If you need an equivalent of Haskell's unsafe_perform_io, and it seems you do,
you can build it yourself like this:

promise_pure (
  some [!IO] (
    io.unsafe_get_io_state(!:IO),
    ...,
    io.unsafe_set_io_state(!.IO)
  )
)

unsafe_{get,set}_io are the primitives that the compiler uses
to implement trace [io(!IO)]. We don't advertise them, since we want to
discourage their use, but there is no point in hiding them either,
because it is trivial to implement them using foreign_procs anyway.

Zoltan.


More information about the users mailing list