ANN: H98 FFI Addendum 1.0, Release Candidate 10
Manuel M T Chakravarty
chak@cse.unsw.edu.au
Sun, 08 Jun 2003 22:36:48 +1000 (EST)
Ross Paterson <ross@soi.city.ac.uk> wrote,
> In 3.3, after the sin example, add:
>
> + Such a declaration asserts that the external entity is a true function,
> + i.e. when applied to the same argument values it always produces the
> + same result.
Done.
> In 5.1, change:
>
> - Furthermore, \code{Foreign} provides the following function:
> ---
> + Sometimes an external entity is a pure function, except that it passes
> + arguments and/or results via pointers. To permit the packaging of
> + such entities as pure functions, \code{Foreign} provides the following
> + primitive:
>
> Rationale: it's not a function, and this wording limits its purpose.
Done.
> - \item[unsafePerformIO ::\ IO a -> a] Execute an \code{IO} action in place of a
> - pure computations. For the behaviour to be predictable, the IO computation
> - should be free of side effects and independent of its environment.
> ---
> + \item[unsafePerformIO ::\ IO a -> a]
> + Return the value resulting from executing the \code{IO} action.
> + This value should be independent of the environment;
> + otherwise, the system behaviour is undefined.
Done.
> Having washed our hands of unsafePerformIO applied to non-deterministic
> actions, we no longer need the third paragraph, which (though scary)
> provides no useful guidance:
>
> - Great care should be exercised in the use of this function. Not only
> - because of the danger of introducing side effects, but also because
> - \code{unsafePerformIO} may compromise typing, for example, when it is used
> - in conjunction with polymorphic references.
I don't quite agree with this. John's IORef example is
indeed outlawed by the determinism requirement. However, it
is possible to construct examples that are deterministic,
but still dubious from a typing perspective. Let's assume a
C routine
void *foo();
that *always returns the same pointer* to a buffer area. To
bind this in Haskell as
foreign import ccall foo :: Ptr a
is problematic[1]. Using peek and poke, we can eg write a
Char and read an Int. One might argue that this is not
quite as bad as for IORef's, because the type argument to
`Ptr' is a dummy anyway and we have `Ptr.castPtr' to convert
between pointers of different type. However, it avoids an
explicit `castPtr', which is not nice.
Moreover, we could use a stable pointer to store a reference
to an IORef in C land and use this to construct something
not unlike John's example. In contrast, to John's example,
we would always get the same IORef (so the function is
deterministic), but could still give it the polymorphic type
that it shouldn't have.
Cheers,
Manuel
[1] I haven't explicitly used `unsafePerformIO' in this
example, but binding C functions with a pure type is
essentially the same thing. In fact, they are a short
hand for binding the function with an IO type and then
using `unsafePerformIO' to obtain the same function with
a pure type.