[mercury-users] Higher-order semideterminism in discriminated unions
André Platzer
api at gmx.de
Wed Aug 27 01:04:31 AEST 2003
David Overton wrote:
>On Tue, Aug 26, 2003 at 12:36:02PM +0200, api at gmx.de wrote:
>
>
>>Hello!
>>
>>When working with higher-order predicates that get a function as an
>>argument and have to store in a data structure defined by a
>>discriminated union, everything works only when the declared determinism
>>of the function argument is det. But as soon as it is changed to semidet
>>or worse, the compiled program crashes with a segmentation fault at
>>runtime. Also the mercury debugger produces invalid results.
>>
>>For example
>>:- module tst_hol_semidet.
>>:- interface.
>>:- import_module io.
>>
>>:- pred main(io__state::di, io__state::uo) is det.
>>
>>:- type storage(Y).
>>:- pred do(func(string)=Y, storage(Y)) .
>>:- mode do(in(func(in)=out is semidet), out) is det.
>>
>>:- func use(storage(Y), string) = Y.
>>:- mode use(in, in) = out is semidet.
>>
>>:- implementation.
>>:- import_module string, require.
>>
>>:- type storage(Y) ---> store(func(string)=Y).
>>
>>do(F, store(F)).
>>
>>use(store(F), A) = F(A).
>>
>>main -->
>> {do(
>> (func(A::in) = ((A ++ "1")::out) is semidet
>> :- A \= "No"
>> ),
>> Storage
>> )},
>> { Res1 = use(Storage, "Yes") ->
>> R1 = Res1
>> ;
>> error("Dunno Yes")
>> },
>> print(R1),
>>
>> { Res2 = use(Storage, "No") ->
>> R2 = Res2
>> ;
>> error("Dunno No")
>> },
>> print(R2)
>> ;
>> {error("did not work")}.
>>
>>
>>Contrary to the det version, this program crashes with
>>*** Mercury runtime: caught segmentation violation ***
>>This may have been caused by a stack overflow, due to unbounded
>>recursion.
>>exiting from signal handler
>>
>>
>
>This appears to be a bug in the mode analyser in the compiler. It
>should report a mode error for predicate do/2 because the higher-order
>value "loses" its higher-order mode information when it is stored in the
>data structure. This is supposed to be disallowed for function terms so
>that the assumption you quoted from the reference manual is safe.
>
>I'll have a look at fixing that bug, but to get this to work you need to
>change your code so that the store has the information that the function
>it contains is semidet. E.g. add an inst
>
> :- inst store_semidet ---> store(func(in) = out is semidet).
>
>and change the mode declarations to
>
> :- mode do(in(func(in) = out is semidet), out(store_semidet)) is det.
> :- mode use(in(store_semidet), out) is semidet.
>
>
>
>>>From the manuals I quote the "higher-order mode" section from which I
>>understand that Determinism=semidet should be legal.
>>
>>"In order to call a higher-order term, the compiler must know its
>>higher-order inst. This can cause problems when higher-order terms are
>>placed into a polymorphic collection type and then extracted, since the
>>declared mode for the extraction will typically be `out' and the
>>higher-order inst information will be lost. To partially alleviate this
>>problem, and to make higher-order functional programming easier, if the
>>term to be called has a function type, but no higher-order inst
>>information, we assume that it has the default higher-order function
>>inst `func(in, ..., in) = out is Determinism'."
>>
>>Does anyone know what to do then? I have tried to use instantiatedness
>>information for the storage but without success.
>>
>>
>
>Have you tried the approach I describe above? That should work
>(although I haven't tested it).
>
Erm, yes thanks. Of course you are right, in the simplified example I
have provided this really solves the problem. But in my real application
scenario, unfortunately this cannot be applied - as far as I know.
Actually, storage is a typeclass so the example had better been like this
:- module tst_hol_semidet2.
:- interface.
:- import_module io.
:- pred main(io__state::di, io__state::uo) is det.
:- inst store_semidet ---> store(func(in) = out is semidet).
:- typeclass storage_class(Storage) where [
some [Y] pred use(string, Y, Storage, Storage),
mode use(in, out, in/*(store_semidet)*/, out/*(store_semidet)*/) is det
].
:- some [Storage] (pred do(func(string)=Y, Storage) =>
storage_class(Storage)).
:- mode do(in(func(in) = out is semidet), out/*(store_semidet)*/) is det.
:- implementation.
:- import_module string, require, std_util.
:- type storage(Y) ---> store(func(string)=Y).
:- instance storage_class(storage(Y)) where [
(use(A, F(A), store(F), store(F)))
].
do(F, store(F)).
:- func cast_det(T::in) = (S::out) is det.
cast_det(X) = Y :-
univ_to_type(univ(X), Y)
;
error("casting failed").
main -->
{do(
(func(A::in) = ((A ++ "1")::out) is semidet
:- A \= "No"
),
Storage
)},
{ use("Yes", Res1, Storage, Storage1) ->
R1 = cast_det(Res1) `with_type` string
;
error("Dunno Yes")
},
print(R1),
{ use("No", Res2, Storage, Storage2) ->
R2 = cast_det(Res2) `with_type` string
;
error("Dunno No")
},
print(R2)
;
{error("did not work")}.
Here, the desired instantiatedness cannot be guaranteed at the
invocation of use/4 since the appropriate mode will be declared in the
typeclass storage/1. But this typeclass cannot know of the individual
instantiatedness trees of its respecitve instances. So the
instantiatedness restrictions /*(store_semidet)*/ cannot be uncommented.
Thus still the problem persists. What am I to do now?
P.S. By the way, what's the difference between the following two
:- inst store_semidet1 ---> store(func(in) = out is semidet).
:- inst store_semidet2 == bound(store(func(in) = out is semidet)).
--------------------------------------------------------------------------
mercury-users mailing list
post: mercury-users at cs.mu.oz.au
administrative address: owner-mercury-users at cs.mu.oz.au
unsubscribe: Address: mercury-users-request at cs.mu.oz.au Message: unsubscribe
subscribe: Address: mercury-users-request at cs.mu.oz.au Message: subscribe
--------------------------------------------------------------------------
More information about the users
mailing list