Je veux intégrer un objet Java (dans ce cas un bufferedimage) dans le code de clojure qui peut être Création du code fonctionne bien: P> eval code> d ultérieurement.
(defn f [image]
(fn [] (.getRGB image 0 0)))
3 Réponses :
Je suppose que vous devriez écrire une macro qui prend l'objet (ou un moyen de créer l'objet requis) lors de la compilation, sérialisez cet objet au format binaire (réseau d'octets) et la sortie de la macro devrait être - Symbole qui se réfère à la matrice d'octets et à une fonction pouvant être utilisée pour obtenir l'objet à partir des données sérialisées en la désémarifiant. P>
Pourquoi la sérialisation est-elle nécessaire? Le code compilé dépend de l'ensemble des octets externes de toute façon, alors pourquoi ne pas en faire un tableau d'objet et conserver la référence à l'objet d'origine là-bas?
Fondamentalement, lorsque la macro sera évaluée qui compilera l'heure, pour ex: (Incord-ressource "My-File.JPEG") code>, la ressource macro intégrée va lire le fichier et stocké celui-ci en tant que Java Array In Code, cela vous permettra d'intégrer l'image dans le code lui-même
Merci, je pense que je l'obtiens maintenant. Si je comprends bien correctement, vous pouvez également sérialiser l'objet immédiatement lors de la génération du code (dans la fonction f code> dans l'exemple de OP), non?
Vous n'êtes pas sûr de ce que vous en avez besoin, mais vous pouvez créer un code qui évite vers un objet arbitraire à l'aide de la triche suivante: alors vous pouvez: p> Il s'agit simplement d'une preuve de concept et il fuit les objets produits - vous pouvez produire du code qui supprime la référence sur eval, mais vous ne pouvez ensuite l'évaluer qu'une seule fois. P> Modifier STROND>: Les fuites peuvent être empêchées par le suivant (Evil!) Hack: p> Le code ci-dessus contourne le compilateur d'Eval's en stockant la référence d'objet à l'extérieur du code généré. Cela peut être différé. La référence d'objet peut être stockée dans le code généré avec le compilateur en cours de contournement par une macro. Stocker la référence dans le code signifie que le collecteur des ordures fonctionne normalement. P> La clé est la macro qui enveloppe l'objet. Il fait quelle est la solution d'origine (c'est-à-dire stocker l'objet à l'extérieur pour contourner le compilateur), mais juste avant la compilation. L'expression générée récupère la référence externe, puis supprime d'éviter les fuites. P> Remarque: C'est le mal fort>. L'expansion des macros est la place la moins souhaitable pour les effets secondaires globaux et c'est exactement ce que cette solution fait. P> maintenant pour le code: p> Voici où stockera temporairement les objets, clés par des touches uniques (dictionnaire). p> C'est la macro diabolique qui se trouve dans le code généré, en gardant la référence à l'objet dans x code> et une clé unique dans
sym code>. Avant la compilation, il stocke l'objet dans le dictionnaire externe sous la touche
sym code> et génère le code qui la récupère, supprime la référence externe et renvoie l'objet récupéré. P>
(defn make-code-that-evals-to [x]
(let [s 17] ; please replace 17 with a generated unique key. I was lazy here.
`(objwrap ~x ~s)))
bonne idée! mais je suis d'accord que la mémoire de la mémoire fait un un peu méchant
@Mikera j'ai une idée de la réparer, je modifierai quand le temps le permet :)
@Mikera Solution ajoutée. Serait toujours chercher un moyen de contourner cela, car cela semble aller contre le grain.
Pourquoi pas: (défmacro m [img] `(.getrgb ~ img 0 0)) Ensuite, vous pouvez écrire: (m une image tamponnée) p>
La différence est que f est une fonction, son argument sera donc évalué avant l'évaluation de son corps. Ainsi, l'objet image lui-même sera placé dans le code généré. Mais pour les macros, leurs arguments ne seront pas évalués. Donc, seul le symbole, une image tamponnée sera placée dans le code. Le code généré sera: (.GETRGBB patère-image-image 0 0). Tout comme vous écrivez le code source directement. Je pense que c'est ce que tu veux. P>
Mais pourquoi ne puis-je pas passer un objet dans le code généré? La réponse est: Oui, vous pouvez. Ce que dit le message d'exception n'est pas la vérité. Vous pouvez intégrer des types d'objets dans le code généré, mais pas toutes les sortes d'entre eux. Ils incluent le symbole, le nombre, le caractère, la chaîne, la regex patten, le mot-clé, le booléen, la liste, la carte, l'ensemble, etc. Tous ces objets seront compris par le compilateur de clojure. Ils sont comme des mots clés, des opérateurs et des littéraux dans d'autres langues. Vous ne pouvez pas exiger que le compilateur de clojure connaisse toutes sortes d'objets, tout comme vous ne pouvez pas nécessiter un compilateur C ou Java connaît tous les mots non inclus par sa syntaxe. P>
est-ce juste évalué cela donne cette erreur? Les macros (par exemple,
si code>) peuvent l'utiliser simplement bien, je suppose? Si oui, alors c'est probablement parce que l'EVAL oblige les choses à passer par le texte (ce qui est logique pour Eval). Si tel est un problème pour vous, vous pouvez utiliser EVAL quand il n'est pas nécessaire - lorsqu'une macro peut être ce dont vous avez besoin.
@andrewkeke comme je le comprends, le
eval code> ne force pas vraiment les choses à parcourir texte i>. Eval (via Compiler) génère un code JVM qui crée les objets. Passer du texte (via la sérialisation) est le dernier recours utilisé sur des objets inconnus.
@Mikera en marche, pouvez-vous commenter pourquoi vous avez choisi d'utiliser la citation et l'évaluation par rapport à faire quelque chose comme
(defn f [a] (fn [] (.GETRGB A 0 0))) code>?
@Mikera Ce serait beaucoup plus simple si vous pouviez simplement cacher les objets Java quelque part et ne pas intégrer ses identifiants dans le code généré. Pourquoi ne peux-tu pas faire ça?