2009-05-03 7 views
4

Je suis très nouveau pour SNL/NJ et je me demandais comment je pouvais accomplir ce qui suit:boucles dans SML/NJ

foo(stuff,counter) 
{ 
    while(counter > 0) 
    { 
    bar(stuff); 
    counter-1; 
    } 
    return; 
} 

Quelque chose comme ça, mais comment puis-je décrémenter ?:

foo(stuff,counter) = 
    while counter > 0 do bar(stuff) ??? // how do I decrement counter here? 

Répondre

6

Dans un programme fonctionnel, une variable mutable se transforme en un paramètre, généralement en une fonction auxiliaire imbriquée.

Puisque dans votre exemple, la chose en cours de mutation est un paramètre constant, aucune fonction auxiliaire n'est nécessaire. Votre code devient

fun foo stuff counter = 
    if counter > 0 then 
    (bar stuff 
    ; foo stuff (counter-1) 
    ) 
    else 
    () 

Bien sûr, ce code est encore terriblement impératif ... L'appel bar stuff est exécuté uniquement pour effet secondaire. Pas très ML-ish.

+1

1 pour le; indentation! – diapir

+0

@diapir: Bah, je donnerais -1 pour ce placement de point-virgule si je m'en souciais plus à ce sujet que sur le contenu. – Svante

+0

@Svante: Je ne sais pas ce qui s'est passé dans ma tête, je lui donnerais 0 tracas en fait. – diapir

5

Réponse courte: Vous ne le faites pas. En programmation fonctionnelle, vous ne modifiez généralement jamais les variables, ce qui signifie qu'une boucle est impossible. Au lieu de cela, vous pouvez implémenter la même chose en utilisant la récursivité. De même, comme vous n'avez généralement pas d'effets secondaires, les appels de fonction n'ont de sens que s'ils renvoient des données. Donc, la barre (stuff) n'est probablement pas très utile. Il n'a aucun moyen d'affecter le reste de l'application. Dans un style de programmation fonctionnel, votre fonction bar() doit être appelée sur des données différentes à chaque fois, et retourner quelque chose sur lequel le reste de l'application peut agir.

(ML ne permet des effets secondaires dans certains cas, mais de garder les choses simples, nous allons ignorer que pour l'instant)

Qu'est-ce que vous essayez d'atteindre exactement? (Qu'est-ce que vous avez besoin de faire une boucle, que font les fonctions?)

Si vous fournissez un peu plus de détails, nous pouvons vous expliquer plus précisément comment vous devriez écrire le programme, mais tel qu'il est, votre programme ne le fait tout simplement pas. sens dans un style fonctionnel.

6

Je suis d'accord avec les autres contributeurs que vous devez utiliser généralement récursion au lieu de boucles et de mutation de le faire dans un langage fonctionnel.

Si vous voulez vraiment utiliser la mutation et des boucles bien , vous devez utiliser une structure de données appelée référence, qui est une sorte de "cellule mutable" Vous attribuez la référence à la fonction ref en lui transmettant le contenu initial. essez le contenu en utilisant l'opérateur !. Et vous définissez de nouveaux contenus en utilisant l'opérateur :=. Donc, la traduction littérale de votre code ci-dessus serait quelque chose comme ceci. Comme vous pouvez le voir, la syntaxe est vraiment moche et c'est une autre raison pour laquelle les gens l'évitent.

fun foo (stuff, counter_start) = 
let 
    val counter = ref counter_start 
in 
    while !counter > 0 do (
    bar stuff; 
    counter := !counter - 1 
) 
end; 
2

Je ne sais pas ML, mais cela est un code pseudo-ML comme:

 
fun foo stuff 0 = return() 
    | foo stuff counter = (bar stuff; foo stuff (counter - 1)) 

Je ne sais pas comment les commandes "chaîne" en ML; le point-virgule est juste un espace réservé.

Généralement, vous ne boucleriez pas. Je préfère attendre les fonctions habituelles d'ordre supérieur. Lorsque vous vous y habituerez, écrire manuellement une boucle vous donnera l'impression de coder l'assembleur.

edit: code fixe selon l'une des observations

+1

C'est à peu près juste, sauf que vous devez placer les commandes chaînées entre parenthèses car le point-virgule a une priorité inférieure à la définition de la fonction. Aussi, je pense que l'OP voulait que l'action soit exécutée 0 fois quand le compteur est 0, donc dans le premier cas, vous ne feriez probablement pas de "truc de barre"; et au lieu de simplement retourner "()" (unité). – newacct

+1

Pour info, il n'est pas nécessaire d'utiliser le mot-clé return en ml. La valeur de retour d'une fonction est toujours la dernière expression de la fonction. – shleim

Questions connexes