Je vagabonder pourquoi Mercury (10,04) ne peut pas déduire le déterminisme du prochain extrait:propriétés ADT dans Mercury
:- pred load_freqs(int::in, io.res(list(float))::out, io::di, io::uo) is det.
load_freqs(CPU, ResFreqs, !IO):-
open_input(cpu_fn(CPU, "available_frequencies"), ResStream, !IO),
(ResStream = io.ok(Stream) ->
ResFreqs = io.ok([])
;ResStream = io.error(Err),
ResFreqs = io.error(Err)
).
Il se plaint:
cpugear.m:075: In `load_freqs'(in, out, di, uo): cpugear.m:075: error: determinism declaration not satisfied. cpugear.m:075: Declared `det', inferred `semidet'. cpugear.m:080: Unification of `ResStream' and `io.error(Err)' can fail. cpugear.m:076: In clause for predicate `cpugear.load_freqs'/4: cpugear.m:076: warning: variable `CPU' occurs only once in this scope. cpugear.m:078: In clause for predicate `cpugear.load_freqs'/4: cpugear.m:078: warning: variable `Stream' occurs only once in this scope.
Mais io.res
ont seulement io.ok/1
et io.error/1
.
Et suivant bout de code compile bien:
:- pred read_freqs(io.res(io.input_stream)::in, io.res(list(float))::out, io::di, io::uo) is det.
read_freqs(io.ok(Stream), io.ok([]), IO, IO).
read_freqs(io.error(Err), io.error(Err), IO, IO).
Mise à jour # 1: Il peut décider det même:
:- pred read_freqs(bool::in, io.res(io.input_stream)::in, io.res(list(float))::out, io::di, io::uo) is det.
read_freqs(no, ResStream, io.ok([]), IO, IO):- ResStream = io.ok(_).
read_freqs(F, io.ok(_), io.ok([]), IO, IO):- F = yes.
read_freqs(yes, io.error(Err), io.error(Err), IO, IO).
read_freqs(F, ResStream, io.error(Err), IO, IO):- ResStream = io.error(Err), F = no.
Dans ce cas, 'ResStream' peut être unifié avec' io.ok (Stream) ', mais peut également être unifié avec' io.error (Err) '. Cela dépend du résultat du fichier d'ouverture. Il y a deux branches pour ça. Pour obtenir une exclusivité "ou" j'utilise la construction "si-le-reste" et comme d'après votre citation cela devrait convenir. Mais Mercure ne peut pas déduire que 'non (ResStream = ok (_)) => ResStream = erreur (_)'. – ony
Dans votre cas, la branche else est 'ResStream = io.erreur (Err), ResFreqs = io.error (Err) 'qui échouera si ResStream est io.ok (X). La règle que j'ai citée ne dit rien sur l'ajout de la négation de la condition. Je suis d'accord que cela pourrait logiquement être ajouté, mais le manuel de référence indique que ce n'est pas le cas. En revanche, les disjonctions sont traitées spécialement si elles ont la forme d'un «interrupteur» - ce qui semble permettre la conjonction dans les disjonctions mais pas les conditionnelles. Je suppose que le raisonnement est que dans le cas courant les motifs ne se croisent pas, et dans ce cas "," et "->" font la même chose. – RD1
Les motifs peuvent se croiser et Mercure trouve ces intersections avec un déterminisme induit "multi". Voir l'exemple supplémentaire. Si vous décidez det. seulement par tête que 'read_freqs' (en mise à jour) sera marqué comme multi. – ony