11
votes

Exécuter la fonction jusqu'à ce que certaines conditions contiennent

Je tiens à appliquer à plusieurs reprises une fonction à un état jusqu'à ce qu'une condition contienne true.

Fonction F prend un état, la modifie et le renvoie. Appliquez F à nouveau à l'état retourné et ainsi de suite. P>

Je pense que cela fonctionnerait. P>

(loop [f x p] (if (p x) x (recur f (f x) p))


0 commentaires

6 Réponses :


4
votes

Vous ne savez pas ce que vous voulez dire par itérateur - vous l'utilisez comme s'il était itérer , et je veux juste être sûr que c'est ce que tu veux dire. En tout cas, votre solution me semble bien et pas du tout laide. Et la mémoire n'est pas une question non plus: itérer est libre de jeter les résultats intermédiaires chaque fois que ce n'est pas pratique, car vous n'en gardez pas de références, appelez simplement filtre une manière "streaming".


1 commentaires

Oui, je voulais dire itérer. C'était une faute de frappe. Mais cela a du sens. J'ai couru cela de sorte que Prey est toujours retourné vrai et je ne reçois pas une exception de mémoire hors mémoire.



0
votes

On dirait que vous voulez que le pendant macro.

http://richhickey.github.com/ clojure / clojure.core-api.html # clojure.core / tandis que

Utilisation: (Pendant le test et le corps) Exécute à plusieurs reprises du corps pendant que l'expression de test est vraie. Présumer Un certain effet secondaire provoquera un test de faux / nil. Retourne nil

Dans un cas d'utilisation légèrement différent, le pour macro prend en charge: Quand et: tandis que les options.

http://richhickey.github.com/ clojure / clojure.core-api.html # clojure.core / pour

Utilisation: (pour SEQ-EXPRS Body-Expr) Compréhension de la liste. Prend un vecteur d'un ou plusieurs Formulaire de liaison / collection-Expr paires, chacun suivi de zéro ou plus modificateurs et donne une séquence paresseuse d'évaluations d'EXPR. Les collections sont itélées à une mode imbriquée, le plus rapide le plus rapide, et Coll-Expres imbriqués peut se référer aux liaisons créées dans l'avant formes de liaison. Les modificateurs pris en charge sont les suivants:: Laissez [formulaire de liaison expr ...], : En test, lors de l'essai.

(prendre 100 (pour [x (gamme 100000000) Y (plage 1000000): tandis que (


2 commentaires

Pas sûr de ce que cela nécessite un effet secondaire. N'a pas pensé à cela, mais pour le fonctionnement, mais vous utiliseriez toujours ITHÉTER (premier (pour [z (itérer f x): tandis que (PRED Z))


Regardez la source de pendant et vous verrez que c'est très comme ce que vous voudriez coder à la main. N'oubliez pas que les données sont immuables dans le clojure, de sorte que «un effet secondaire» dans ce cas pourrait simplement être une mise à jour de l'état de var x.



6
votes

Ce que vous voulez vraiment, c'est : xxx

modifier

Un moyen d'utiliser des fonctions d'ordre supérieur pour obtenir le résultat que vous souhaitez consister à envelopper votre fonction à quelque chose à consommer par < Code> trampoline , nommément une fonction qui renvoie le résultat final ou une autre fonction qui exécutera la prochaine étape. Voici le code: xxx

L'exécution itérative irait comme suit: xxx


0 commentaires

2
votes

Je ne pense pas qu'il y ait une fonction de base qui le fait exactement et efficace. Par conséquent, je le ferais avec une boucle / recur comme suit: xxx

boucle / recur est très efficace car il ne nécessite aucun stockage supplémentaire et est implémenté comme une boucle simple dans la JVM.

Si vous allez le faire beaucoup, vous pouvez toujours encapsuler le motif dans une macro.


3 commentaires

Je suis d'accord avec votre réponse, sauf que cela n'a pas besoin d'être une macro? Une simple fonction récursive fonctionnerait également aussi bien?


@dbryne Bien sûr - vous pouvez aussi faire une fonction si vous le souhaitez. Bien que dans ce cas, je pense que je préférerais une macro - vous obtiendriez une efficacité d'exécution légèrement meilleure, et j'ai tendance à préférer les macros pour tout ce qui ressemble à une "structure de contrôle".


Je conviens que c'est la solution la plus efficace. Et c'est ce que j'aurais fait si ce n'était pas juste pour la pratique. Un avantage est qu'il est facile de raisonner sur la performance. Si cela était quelque chose que j'allais utiliser beaucoup, j'utiliserais une fonction. Je pense que ce type de fonction pourrait être inlincé par la JVM, donc je ne sais pas pourquoi vous voudriez utiliser une macro.



4
votes

Je pense que vous devriez simplement faire une boucle une fonction récursive simple: xxx


1 commentaires

Oui, bien sûr, c'est une bonne solution. Mais il est bon de pratiquer l'utilisation des fonctions d'ordre supérieur dans la bibliothèque principale à une récursion abstraite abstraite. Au fait, j'appellerais cela, jusqu'à ce que. Ce serait bien d'avoir quelque chose comme celui-ci dans la bibliothèque principale.



3
votes

Que diriez-vous de supprimer

(first (drop-while (comp not pred) (iterate f x))


0 commentaires