2010-07-29 5 views
3

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. 

Répondre

2

Ma lecture des règles de mercure pour le déterminisme avec conditionals (ci-dessous) est que pour cela être considéré comme déterministe, vous devez remplacer le -> par un ,

du Mercury re manuel Conférence:

Si l'état d'un if-then-else ne peut pas échouer, l'if-then-else est équivalente à la conjonction de la condition et la partie « then », et son déterminisme est calculé en conséquence. Sinon, un if-then-else peut échouer si la partie "then" ou la partie "else" peut échouer.

+0

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

+1

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

+0

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

1

Ok, il peut déduire det pour:

:- 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(0, "available_frequencies"), ResStream, !IO), 
    (ResStream = io.ok(Stream), 
     ResFreqs = io.ok([]) 
    ;ResStream = io.error(Err), 
     ResFreqs = io.error(Err) 
    ). 

Mais pourquoi la construction "if-then-else" introduit semidet?

+1

Ma première réponse à "pourquoi?" C'est parce que c'est ce que dit le manuel de référence Mercury. Mais, je suppose que vous voulez dire "pourquoi Mercure est-il conçu de cette façon?". Je suppose que les commutateurs doivent être traités d'une manière spéciale, et les concepteurs ne voulaient pas les rendre plus compliqués que nécessaire, et éviter les informations négatives simplifie vraiment les choses. De plus, j'ai l'impression que Mercury encourage généralement les commutateurs de préférence aux conditionnels. En effet, il y a un commutateur --inform-ite-au lieu-de-switch pour activer le reporting des conditions qui devraient être remplacées par des commutateurs. – RD1

+0

Merci, c'est une option utile "--inform-ite-au lieu-de-commutateur". – ony

2

Comme pour 'Pourquoi'. permet de regarder le code original avec if-then-else:

(ResStream = io.ok(Stream) -> 
    ResFreqs = io.ok([]) 
;ResStream = io.error(Err), 
    ResFreqs = io.error(Err) 
). 

Si la condition échoue, la première dans le cas en conjonction avec d'autres est un test semidet. Le compilateur ne sait pas qu'il doit réussir (ce qui peut être inféré par la connaissance que cette condition a échoué). En d'autres termes, le compilateur n'est pas assez intelligent. Cela dit, il est rare de trouver ce problème, car la condition est généralement plus compliquée et ne permet pas cette inférence, il n'est donc pas important que le compilateur ne soit pas assez intelligent pour déterminer le déterminisme correct. ici.

Il est recommandé de programmer à l'aide de commutateurs autant que possible (comme dans cet exemple), cela évite le problème actuel et aide à s'assurer que vous avez couvert tous les cas possibles de ResStream. Par exemple, si dans le futur io.error était factorisé et pourrait être io.error_file_not_found ou io.error_disk_full etc, le compilateur ordonnerait au programmeur de réparer son switch car il serait maintenant incomplet.

+0

A ce moment, pour moi, c'est plus facile à comprendre par '(X = oui, vrai, non (X = oui), X = non)' (c'est ce que j'attends de '(X = oui -> vrai; X = non) ') sera déduite de nondet à cause de' not/1'. – ony

+0

C'est vrai jusqu'à ce que la situation devienne plus compliquée. Si il y a plus de symboles que oui ou non, ou s'il y a plus d'une unification dans la condition. –

Questions connexes