Il y a beaucoup de postes liés à cela, mais je le pose à nouveau avec un but différent fort> J'essaie de comprendre pourquoi les fermetures sont importantes et utiles. Une des choses que j'ai lues dans d'autres messages en ce qui concerne cela est que lorsque vous passez une variable à la fermeture, la fermeture commence à se souvenir de cette valeur à partir de là. Est-ce l'ensemble de l'aspect technique ou il y a plus à ce qui se passe là-bas. P> Ce que je me demande, c'est ce qui se passerait lorsque la variable utilisée à l'intérieur de la fermeture est modifiée de l'extérieur. Si celles-ci ne sont que des constantes seulement? P> Dans le clojure de langue, je peux faire ce qui suit: mais comme il y a de la valeur est immuable, ce problème ne se présente pas. Qu'en est-il des autres langues et quelle est la définition technique appropriée d'une fermeture? P>
8 Réponses :
Vous pouvez penser à une fermeture comme un "environnement", dans lequel les noms Si vous aimez, vous pouvez penser à un environnement comme dictionnaire ou table de hachage. Une fermeture obtient son propre petit dictionnaire où les noms sont levés. P>
Il est un peu trompeur de dire que les noms de fermeture sont liés à valeurs i>. Dans certaines langues (par exemple Smalltalk), ils sont liés à références i>. Dans SmallTalk, deux fermetures peuvent "fermer" une variable locale x code> et ils se verront les affectations de chacun à
x code>.
D'accord, et j'ai pensé avec précaution sur mon choix de mots, envisageez mon auditoire. :)
Une fermeture est en réalité une structure de données utilisée par le compilateur pour vous assurer qu'une fonction aura toujours accès aux données nécessaires à l'opportunité. Voici un exemple de fonction qui enregistre quand il a été défini.
(defn outer [] (let [foo (get-time-of-day)] (defn inner [] #(str "then:" foo " now:" (get-time-of-day))))) (def then-and-now (outer)) (then-and-now) ==> "then:1:02:03 now:2:30:01" .... (then-and-now) ==> "then:1:02:03 now:2:31:02"
a fermeture lexicale em> est un dans lequel les variables ci-jointes (par exemple Dans des langues fonctionnelles pures, ce n'est pas une grande distinction, car les valeurs ne sont jamais changées. Donc, peu importe si la valeur de Dans "Imperative-Languages-avec fermetures", telles que C # et Java (via des classes anonymes), une décision doit être faite sur le point de savoir si la variable ci-jointe est jointe à une valeur ou par référence. En JAVA, cette décision est préemptée en permettant uniquement aux variables de Englobant par la valeur simplifie la mise en oeuvre: la variable à clôturerie existe souvent sur la pile et sera donc détruite lorsque la fonction construit la fermeture de la fermeture - cela signifie qu'il ne peut pas être enfermé par référence. Si vous avez besoin d'un boîtier par référence, une solution de contournement consiste à identifier de telles variables et à les conserver dans un objet attribué chaque fois que cette fonction est appelée. Cet objet est ensuite maintenu dans le cadre de l'environnement de la fermeture et doit rester en direct tant que toutes les fermetures en utilisant sont en direct. (Je ne sais pas si des langues compilées utilisent directement cette technique.) P> préfixe de message d'accueil code> dans votre exemple) sont jointes à la référence. La fermeture créée ne reçoit pas simplement la valeur de
préfixe de message d'accueil code> au moment de sa création, mais obtient une référence. Si
VOYAGE-PREFIX CODE> est modifié après la création de la fermeture, sa nouvelle valeur sera utilisée par la fermeture chaque fois qu'elle est appelée. P>
de préfixe-préfixe code> est copiée dans la fermeture: il n'y a pas de différence possible de comportement qui pourrait résulter de se référer à l'original par rapport à sa copie. P>
final code> à imiter efficacement une langue fonctionnelle en ce qui concerne cette variable. En C #, je crois que c'est une question différente. P>
Vous pourriez aimer lire sur lambdas, capture et mutabilité a>, qui décrit comment cela fonctionne dans C # et F #, à comparaison. P>
Jetez un coup d'œil à ce blog post: Adts in Clojure . Il montre une agréable application de fermetures au problème des données de verrouillage de manière à ce qu'elle soit accessible exclusivement via une interface particulière (rendu du type de données opaque).
L'idée principale de ce type de verrouillage est plus simplement illustrée avec le compteur Exemple, quel huaiyuan a posté en commun Lisp pendant que je pouvais composer cette réponse. En réalité, la version de Clojure est intéressante en ce sens qu'elle montre que la question d'une variable de changement fermé changeant sa valeur est survenue dans le clojure si la variable arrive à contenir une instance de l'un des types de référence. P>
((make-greeter "Hello from Gizmos Dept") "John") ((make-greeter "Hello from Gadgets Dept") "Jack").
Pour plus de descriptions, voir par exemple: p>
HypersPec de Lisp, 3.1.4 Fermetures et Reliure lexicale p>
et p>
Common Lisp La langue, 2e édition, chapitre 3., Portée et l'étendue p>
Ce n'est pas le genre de réponse qui semble avoir des votes utiles ici, mais je vous exhorte tout à fait envie de découvrir la réponse à votre question en lisant Shrram Krishnamurthi's (gratuit!) (en ligne!) manuel, Langues de programmation: Application et interprétation . P>
Je vais paraphraser le livre très, très em> brièvement, en résumant le développement des minuscules interprètes qui vous conduisent à travers: p>
Ceci est le point clé: vous mettez en œuvre cela, puis vous découvrez cela avec la substitution, cela fonctionne bien, mais avec des environnements, il est cassé. En particulier, afin de le réparer, vous devez vous assurer d'associer à une définition de fonction évaluée de l'environnement qui était en place lorsqu'il a été évalué. Cette paire (Fundef + Environnement de définition) est ce qu'on appelle une "fermeture". P>
whew! em> p>
D'accord, que se passe-t-il lorsque nous ajoutons des liaisons mutables à la photo? Si vous essayez ceci vous-même, vous verrez que la mise en œuvre naturelle remplace un environnement qui associe des noms avec des valeurs avec un environnement qui associe des noms avec des liaisons. C'est orthogonal à la notion de fermeture; Étant donné que la fermeture Capturing Environnements, et puisque les environnements sont désormais de noms de noms vers des fixations, vous obtenez le comportement que vous décrivez, dans lequel la mutation d'une variable capturée dans un environnement est visible et persistante. P>
Encore une fois, je vous exhorte beaucoup à vous demander de jeter un coup d'œil à Plai . P>
Votre réponse pourrait être améliorée en fournissant un lien hypertexte sur le site du livre - et non qu'il est trop difficile de trouver, mais c'est une bonne faveur.
Vous pouvez penser à une fermeture en tant que "environnement", dans lequel les noms sont lié aux valeurs. Ces noms sont entièrement privé à la fermeture, qui C'est pourquoi nous disons qu'il "ferme" " son environnement. Donc votre question n'est pas significatif, dans ce "extérieur" ne peut affecter la environnement fermé. Oui un la fermeture peut faire référence à un nom dans un environnement mondial (en d'autres termes, si il utilise un nom qui n'est pas lié dans son environnement privé, fermé), Mais c'est une histoire différente. P>
Je suppose que la question était de savoir si des choses comme celles-ci sont possibles dans des langues qui permettent la mutation des variables locales: p>
xxx pré> et - car ils sont évidemment possibles - je pense que la question est légitime. p> blockquote>