10
votes

Style de clojure: Defn- vs. Letfn

style de clojure (et bonne ingénierie logicielle en général) met l'accent sur de nombreuses petites fonctions, dont un sous-ensemble sont publiquement visibles pour fournir une interface externe.

dans le clojure, il semble y avoir quelques façons de faire cela : P>

(letfn [(private-a ...)
        (private-b ...)]
  (defn public-a ...)
  (defn public-b ...))

(defn- private-a ...)
(defn- private-b ...)
(defn public-a ...)
(defn public-b ...)


0 commentaires

3 Réponses :


6
votes

Le but de letfn est totalement différent de celui du formulaire defn . Utilisation de Letfn au niveau supérieur ne vous donne pas les mêmes propriétés de DEFN, car toutes les liaisons de noms de noms aux fonctions liées à l'intérieur LetFN n'est pas visible en dehors de sa portée. La reliure pour les fonctions liées à l'intérieur let ou letfn n'est pas disponible en dehors de sa portée lexicale. De plus, la visibilité des fonctions liées à l'intérieur letfn est indépendante de l'ordre dans lequel ils sont liés à l'intérieur de cette portée lexicale. Ce n'est pas le cas avec let.


1 commentaires

@Thumbnail Vars a été un mauvais terme à utiliser. J'ai essayé de réparer les termes.



13
votes

letfn est destiné à être utilisé dans des cas de récursivité mutuelle: xxx

ne l'utilise pas au niveau supérieur.

aussi N'utilisez pas le defn macro ailleurs qu'au niveau supérieur à moins que vous ayez des raisons très spécifiques. Il sera étendu au formulaire spécial def qui créera et stagiaire global var.


7 commentaires

Vous sentez-vous que letfn n'est généralement pas approprié pour les fonctions d'assistance en général - une utilisation utilisée2494739 mentionnée - mais uniquement pour une récursion mutuelle? Je n'ai aucune idée de ce qui est couramment fait avec letfn , donc je peux être idiosyncratique, mais je définis souvent des fonctions d'assistance à l'aide de letfn , ou parfois (let [F (fn [x] ...) ...] Pour éviter d'utiliser Laisser et Letfn ensemble.


Je pense en utilisant letfn ou (let [fn [x] ... comme ça va bien. Je fais cela tout le temps moi-même. Cela réduit le nombre de fonctions. Vous avez défini au niveau supérieur, que je considère comme une bonne chose.


Pour clarifier, cependant, j'utilise letfn dans a defn . Quelque chose comme (defn haut niveau-fn-fn [xs] (letfn [(assistant [Y] (faire-chose-avec y))] (Map Helper XS)))


Droit - même ici, @Daveyarwood. Je suppose que cela ne me dérangerait pas beaucoup avoir une fonction supplémentaire de haut niveau, en soi, mais letfn rend évident que c'est juste là comme assistant pour le DEFN fonction ED, et que est une bonne chose, en plus de réduire le nombre de fonctions de niveau supérieur.


J'utilise letfn uniquement en cas de récursivité mutuelle. Dans tous les autres cas (Let [fn ... suffit et offre plus de possibilités contraignantes.


Illicitement rien de mal à utiliser letfn pour des fonctions d'assistance générale, y compris au niveau supérieur. Un exemple de ceci dans le sauvage est le piédestal Moteur de Dataflow . Je ne suis pas affilié - juste un exemple aléatoire à partir d'un projet "sérieux" par des clojures crédibles.


@jbm Même si l'exemple a été écrit par "Couvertibles Crojure Folks", je ne considère pas le bon style: 1. Le seul but qu'il sert, c'est clair pour un lecteur humain que ces deux fonctions ne sont utilisées que dans le DEFN forme de son corps. 2. E. g. Un outil d'analyse de code reposant sur les métadonnées source de la fonction d'affichage de la source dans une IDE sera bloqué Résoudre les deux FNS.



4
votes

Mes règles sont celles-ci:

  • Si une fonction subsidiaire est utilisée dans un publique, définissez-la localement avec laissez ou letfn .
  • S'il est utilisé dans plusieurs, définissez-le au niveau supérieur avec defn - .

    et

    • n'utilise pas let ou letfn au niveau supérieur.
    • n'utilise pas def ou defn ou defn - n'importe où autre que le niveau supérieur.

2 commentaires

J'utilise un canal pour permettre la communication entre deux fonctions privées et ma fonction principale et utiliser: (que [C (Chan)] (Defn-B ...) (DEFN-B ...) Principal (A ...) (B ...))) Cela ne serait-il pas bon?


@Peter, je ne dirais pas que c'est dommage si vous avez vraiment besoin d'une transformation et d'une étatabilité. Soyez averti, cela causera des problèmes de concurrence.