2011-09-24 3 views
4

Je suis nouveau à Common Lisp, et je me suis retrouvé en profitant des fonctions de la fonction retourne des valeurs. Voici deux exemples triviaux:Un bon moyen de programmer en Lisp?

(defun safe-avg (a b) 
    (and (numberp a) (numberp b) (/ (+ a b) 2))) 

(defun safe-div (a b) 
    (and (numberp a) (numberp b) (> b 0) (/ a b))) 

Mais je aurais pu l'écrire comme ça (sans doute plus clair):

(defun safe-avg (a b) 
    (if (and (numberp a) (numberp b)) 
     (/ (+ a b) 2))) 

(defun safe-div (a b) 
    (if (and (numberp a) (numberp b) (> b 0)) 
     (/ a b))) 

Je voulais savoir quelle est la méthode préférée de faire quelque chose comme ça et le raisonnement derrière cela, avant que je commence à abuser de cette habitude.

+0

J'utiliserais la 2ème forme. Pourquoi? Parce que c'est "moins difficile" et montre mieux l'intention. J'apprécie la lisibilité du code - à la fois maintenant et dans 6 mois à partir de maintenant. –

+0

J'étais habitué à schématiser, êtes-vous sûr que la fonction est équivalente? Pour moi pas, comme le premier couple de fonction renvoie false si la contrainte ne sont pas satisfaire le second ne semble pas spécifier une valeur de retour – Eineki

Répondre

7

Puisque vous n'utilisez pas la branche "else", vous pouvez utiliser when:

(defun safe-div (a b) 
    (when (and (numberp a) (numberp b) (> b 0)) 
    (/ a b))) 

qui est le même que:

(defun safe-div (a b) 
    (if (and (numberp a) (numberp b) (> b 0)) 
     (/ a b) 
     nil)) 

qui est la même chose que votre version, mais plus explicite.

Quoi qu'il en soit, toutes ces fonctionnalités sont équivalentes. Je préférerais réfléchir à la façon dont ces fonctions doivent être utilisées. Si vous le faites comme ça, vous devrez faire des vérifications nuls chaque fois que vous appelez ces fonctions, ce qui est fastidieux.

Il serait préférable d'utiliser des conditions, soit par le biais de déclarations de type, soit par le biais d'assertions, soit par l'intermédiaire de when & hellip; signal formes. Vous pouvez ensuite définir des gestionnaires et des redémarrages pour ces conditions pour des parties entières de votre programme. Pour en savoir plus: Practical Common Lisp, ch. 19.

Dans ce cas, je ne serais pas ici gérer cela du tout:

(defun safe-div (a b) 
    (/ a b)) 

(ou plutôt, il suffit d'utiliser /). Si / obtient les mauvais arguments, il signalera une erreur que vous pouvez ensuite gérer à l'extérieur, où vous savez ce que cela pourrait signifier.

3

La première forme est idiomatiquement acceptable. Ce n'est pas le meilleur exemple d'utilisation efficace de la valeur de retour de AND, puisque la seconde forme est un peu plus claire sans être plus longue. Mais vous ne devriez pas avoir peur d'utiliser LISP comme prévu!

Par exemple, aller dans un (à déconseiller) direction ... On pourrait soutenir que le « retour néant » implicite de déclarations if pourrait être source de confusion et d'essayer de la structure parallèle if/else être plus claire:

(defun safe-avg (a b) 
    (cond ((and (numberp a) (numberp b)) 
     (/ (+ a b) 2)) 
     (t 
     nil))) 

C'est mauvais. Et vous ne voulez pas descendre cette route. Alors allez-y et utilisez les expressions et découpez la quantité de code avec de belles évaluations, et utilisez des commentaires pour prendre le relais pour rappeler aux autres (et à vous-même) comment cela fonctionne si quelque chose n'est pas évident.

+0

Quelqu'un downvoted cela, et n'a donné aucune raison (toujours un ennui).Donc, j'ai édité pour être clair que je ne suggère pas que l'échantillon de code est une bonne idée. C'est un exemple délibérément mauvais alors vous vous rendez compte qu'embrasser la «façon LISP» de la programmation est une bonne direction. Mais peu importe. – HostileFork

+0

En fait, j'aime beaucoup l'approche COND. IF et WHEN sont juste du sucre syntaxique pour COND de toute façon. :-) COND est généralement plus clair lorsqu'il y a une ou plusieurs conditions de test. Je dois admettre que j'utilise toujours la RCA et la CDR au lieu des versions politiquement correctes actuelles. –

+0

@ArtTaylor Je l'ai effectivement écrit de cette façon parce que j'ai regardé 'if' et je n'ai pas vu la manipulation d'autre dans la documentation sur le site que j'ai trouvé. (Je ne connais pas le lisp commun en particulier, juste les langages comme ça, et j'ai branché ça dans un interpréteur que j'ai installé et ça a marché.) Point reste, je pense toujours que jeter la clause "nil" au lieu de laisser le retour nul implicitement, c'est trop la mentalité du langage C-style ... – HostileFork

Questions connexes