11
votes

Appliquer une carte à l'argument de repos d'une fonction

dans le clojure, si j'ai une fonction f , xxx

et j'ai un SEQ args avec les arguments que je veux appelez F avec, je peux facilement utiliser appliquer : xxx

maintenant, dites que j'ai une autre fonction g , ce qui est conçu pour prendre un certain nombre d'arguments facultatifs et nommés - c'est-à-dire où l'argument de repos est déstructuré comme une carte: xxx

J'appelle normalement g en faisant quelque chose comme xxx

mais si j'arrive à avoir une carte ma carte avec la valeur {: A 1: B 2}, et je veux "Appliquer" g sur ma carte - En d'autres termes, obtenez quelque chose qui se retrouverait comme l'appel ci-dessus, alors je ne pouvais naturellement pas utiliser s'appliquer, car cela équivaut à xxx

Y a-t-il une bonne façon de gérer cela? Puis-je avoir quitté la piste dans mon design pour finir avec cela? La meilleure solution que je puisse trouver serait xxx

mais je n'aime sûrement pas ça. Toutes meilleures solutions?

EDIT: Une légère amélioration de la solution suggérée peut être xxx

qui supprime au moins une seule fonction Appelez, mais cela ne peut toujours pas être très clair ce qui se passe.


0 commentaires

4 Réponses :


6
votes

Je suis tombé sur ce problème moi-même et j'ai fini par définir des fonctions pour attendre une carte. Une carte peut avoir une quantité variable de paires de clé / de valeur et si suffisamment flexible, il n'y a donc pas besoin d'arguments et de repos. Il n'y a pas non plus de douleur avec Appliquer. Rend la vie beaucoup plus facile! XXX


3 commentaires

Merci! Ce serait certainement un moyen, mais ensuite les arguments facultatifs, nommés que le repos associatif, permettant de mettre aurait toujours besoin d'être mis à l'intérieur d'une carte dans l'appel de la fonction, en particulier, si vous souhaitez utiliser aucun des arguments, vous souhaitez utiliser D avoir à faire (g {}) ou (g nil). Je vois maintenant que je n'étais pas clair dans la question - je modifierai pour préciser que G est conçu pour prendre des arguments nommés facultatifs et que la question serait de savoir comment l'appeler idiomatiquement si vous avez des arguments enveloppés dans une carte.


Vous pouvez également utiliser plusieurs arités, une pour zéro arguments et un pour un argument: (defn g ([] ...) ([{: touches [AB]: comme m}] ...))


Merci! En fin de compte, je suis allé avec cette solution - la raison pour laquelle je me suis retrouvé dans cette situation, la fonction d'origine grandissait grandement et la partie utilisant les arguments facultatifs était bien adaptée pour être cassée dans sa propre fonction H. Je voulais toujours que G soit appelé de la même manière cependant, alors à l'appel à G avec les arguments facultatifs regroupés dans une carte, plutôt que de faire appel à H et à la transmission des résultats à g. Dans ce cas particulier, votre suggestion a bien fonctionné, mais j'ai écrit une fonction simple qui fonctionne bien pour la question initiale - le postera comme une réponse.



3
votes

Il n'y a pas de meilleure façon directe que de convertir à un SEQ.

vous avez terminé. Vous avez fait tout ce que vous pouvez.

Ce n'est tout simplement pas vraiment clojurish d'avoir des fonctions communes de style LISP: mot-clé argument. Si vous regardez autour du code de Clojure, vous constaterez que presque aucune fonction n'est écrite de cette façon.

Même le Grand RMS n'est pas un fan d'eux:

"Une chose que je n'aime pas terriblement beaucoup, c'est des arguments mots clés (8). Ils ne semblent pas assez lispy pour moi; je le ferai parfois mais je minimise les temps quand je le fais." ( source )

Au moment où vous devez casser une carte de hachage complète en morceaux pour les transmettre à tous comme des arguments mappés sur mot-clé, vous devez remettre en question votre conception de la fonction.

Je trouve que dans le cas où vous voulez passer le long des options générales telles que : considérez-nil true Vous n'allez probablement jamais appeler la fonction avec une carte de hachage {: considérer -nil true} .

Dans le cas où vous souhaitez effectuer une évaluation basée sur certaines clés d'une carte de hachage, vous êtes 99% du temps comportant un F ([m & args]) Déclaration.

Quand j'ai commencé à définir des fonctions dans Clojure, j'ai frappé le même problème. Cependant, après avoir réfléchi davantage sur les problèmes que j'ai essayés de résoudre, je me suis remarqué en utilisant la déstruction de la déclaration de fonction presque jamais.


3 commentaires

Vous pourriez bien avoir raison. Je l'ai trouvé utile parfois et je pense que cela vous permet de construire facilement des fonctions assez flexibles, mais je vous assurerai de lui donner une pensée supplémentaire. En ce qui concerne la façon dont je me suis retrouvé dans cette situation, j'ai essayé de donner une brève explication dans mon commentaire à la réponse de Michiel Borkent - je ne sais pas si cela a tout cependant de sens :)


Vous avez mentionné que vous ne vouliez pas appeler h et transmettre les résultats à g. Même sans connaître le domaine du problème, je peux difficilement imaginer de bonnes raisons de faire une telle chose. La conception fonctionnelle consiste à briser de gros problèmes dans de petits problèmes indépendants. Il semble que vous optimisez pour un appel de fonction plus agréable. Si vous décririez les tâches spécifiques que G et H remplissent, je pouvais peut-être répondre à un meilleur jugement.


Je travaille sur un cadre d'automatisation des tests pour le système que mon équipe travaille et j'essaie de travailler une interface simple pour les autres (qui ne sont pas très expérimentées avec le clojure). Pour eux, il n'y aurait pas de point que les fonctions soient bien composables, notamment car H soit principalement signifiée comme une fonction d'aide à g. Je suis tout cependant d'accord avec vous et après avoir donné d'autres pensées, j'ai fait de la refonte, et je faisais simplement une fonction confrontée de manière externe la composition des autres. Un pas en avant ... merci!



1
votes

Voici une fonction très simpliste qui peut être utilisée exactement comme appliquer, sauf que le dernier arg (qui devrait être une carte) sera étendu à: Key1 VAL1: Key2 VAL2, etc.

(defn mapply
  [f & args]
  (apply f (reduce concat (butlast args) (last args))))


0 commentaires

0
votes

Une solution la plus belle que j'ai trouvée: xxx


0 commentaires