7
votes

(Définir (moyenne ....)) dans Lisp

Je joue simplement avec Scheme / Lisp et je pensais à la façon dont je voudrais juste ma propre définition de moyenne . Je ne sais pas comment faire certaines choses que je pense sont nécessaires.

  • Définissez une procédure qui prend un nombre arbitraire d'arguments
  • compter ces arguments
  • passez la liste des arguments à (+) pour les résumer

    Quelqu'un a-t-il un exemple de définition de la moyenne ? Je ne semble pas savoir assez sur Lisp pour former une recherche sur le Web qui récupère les résultats que je recherche.


2 commentaires

Ce ne sont pas des devoirs (a été évité pour une raison quelconque ... probablement parce que quelqu'un a pensé que c'était). Je travaille sur le cours SICP en ligne et je jouais simplement avec Lisp vous demandant comment créer cette période de procédure.


(FWIW, c'était assez clair - presque tous les cours évitent de passer des fonctions avec des arguments de repos.)


5 Réponses :


3
votes

En commun Lisp, on dirait que vous pouvez faire:

[1]> (defun average (&rest args)
       (when args
         (/ (apply #'+ args) (length args))))
AVERAGE
[2]> (average 1 2 3 4 5 6)
7/2


8 commentaires

Vous ne devriez pas supposer qu'une implémentation de LISP peut accepter un nombre quelconque d'intrants (et IIRC, CLISP va casser). En outre, la fonction doit toujours renvoyer un nombre - ce code retournera nul lorsqu'il n'est donné aucune entrée.


@Eli, vous en savez probablement plus sur LISP que moi (comme en témoigne votre réponse beaucoup plus complète). Mais je dois être en désaccord sur cette dernière déclaration. Mathématiquement, la moyenne d'un ensemble NULL n'est pas un nombre, il est indéfini. Si vous voulez que cela retourne 0 {Ugh! Imnsho :-)}, vous pouvez modifier le code pour le faire.


Paxdiablo: Droite, c'est est non défini et la traduction de celle à coder est dans la plupart des cas le mieux fait en lançant une erreur. Voir mon code par exemple: il lancera une erreur lorsqu'il ne donnera aucune entrée (une mauvaise division par zéro dans la première version et une très meilleure erreur d'arité plus tard). Bien sûr, il existe également des cas où vous voudrez renvoyer un résultat "indéfini" ( null , non défini , nan , etc.), mais Habituellement Il est préférable de faire jeter du code une erreur plus tôt, plutôt que de lui permettre de propager un résultat potentiellement faux à travers.


(Oh, et BTW, tout lisper gémirait à "Lisp" - il devrait être "LISP".)


Désolé, je pensais que c'était l'acronymn: beaucoup d'éthérées superflues irritantes :-) Je n'ai jamais joué un peu avec Lisp, plus de régime puisque cela faisait partie d'un produit que nous avons adopté une fois, mais tout ce que je peux me souvenir des deux personnes aujourd'hui est le %% correspondant-correspondant-correspondant que je devais faire dans VI.


Cela semble plutôt que vous n'avez pas configuré votre éditeur correctement.


Ouais - Vous verrez également que les programmeurs LISP / SCHAGHT sont très Pedantic à propos de leur indentation: c'est parce qu'après une courte période initiale de réglage, vous viennent de "ne pas voir" les parens. Cela inclut de nombreuses personnes qui n'entrent jamais un ( sans fermeture ) , donc le code source n'est jamais déséquilibré, ce qui signifie que vous n'avez jamais besoin de les compter - et c'est pratique dans toutes les langues. (Mais bien sûr, cela n'arrête pas les blagues habituelles liées aux paren ...)


Eli pourquoi lisp? Le livre SICP indique que LISP signifie le traitement de la liste. Étant donné que c'est un acronyme, la représentation appropriée ne serait-elle pas dans toutes les casques? Ne disant pas que vous avez tort, vous vous demandez simplement pourquoi Lisp et non Lisp étant donné cette définition.



11
votes

La définition serait une très simple doublure, mais sans gâcher, vous devriez examiner:

  • un "repos" argument - ce (définir (foo. xs) ... xs ...) définit foo en tant que fonction qui prend N'importe quel nombre d'arguments et ils sont disponibles en tant que liste qui sera la valeur de XS .

  • longueur retourne la longueur d'une liste.

  • Apply prend une fonction et une liste de valeurs et applique la fonction à ces valeurs.

    Lorsque vous obtenez cela, vous pouvez aller pour plus:

    • Voir la fonction FILEL Pour éviter d'appliquer une liste sur une liste potentiellement très grosse (cela peut compter sur certaines implémentations dans lesquelles la longueur de la liste des arguments est limitée, mais ce ne serait pas faire beaucoup de différence dans la raquette).

    • Notez que Raquette a des rationnels exacts et que vous pouvez utiliser exacte-> inexacte pour créer une version plus efficace du point flottant.





      et les spoilers sont:

      • (définir (moyenne. NS) (/ (appliquer + ns) (longueur ns)))

      • Il faut avoir besoin d'un argument: (Définir (N. N. Ns) (/ (Appliquer + N NS) (Add1 (Longueur NS))))

      • Utilisez plipl : (Définir (N. Moyen ns) (/ (FILETL + 0 (CONNE NS)) (Add1 (Longueur NS))))

      • Faites-le utiliser le point flottant: (définir (N. moyen NS) (/ (FILETL + 0,0 (CONNE NS)) (Add1 (Longueur NS))))


0 commentaires

1
votes

Dans le schéma, je préfère utiliser une liste au lieu de l'argument "REST", car l'argument de repos fait des procédures de mise en œuvre, telles que les éléments suivants:

(defun average (the-list)
  (let ((count 0) (sum 0))
    (dolist (n the-list)
      (incf count)
      (incf sum n))
    (/ sum count)))


3 commentaires

Vous pouvez utiliser appliquer pour traduire la liste dans une liste d'arguments.


(incc. sum n) est meilleur que (SUMEF SUM (+ SUM N)) . En outre, mon premier prototype serait généralement (/ (réduisant # + liste) (Liste de longueur)) , puis je pourrai le changer en un (boucle pour l'élément de comptage de la liste dans Longueur Summing Element en somme enfin (retour (/ sommet))) .


Ne pouviez-vous pas écrire à la place d'une macro simple pour déballer la liste comme des arguments individuels pour appeler moyen de sorte qu'il ressemblerait à: (définir la moyenne (NS) (NS) ))) ? Je suis actuellement un nouveau système / Lisp Newbie, alors je ne sais honnêtement pas ce que cela est possible.



2
votes

Deux versions en commun LISP:

(defun average (items)
  (destructuring-bind (l . s)
      (reduce (lambda (c a)
                (incf (car c))
                (incf (cdr c) a)
                c)
              items
              :initial-value (cons 0 0))
    (/ s l)))

(defun average (items &aux (s 0) (l 0))
  (dolist (i items (/ s l))
    (incf s i)
    (incf l)))


0 commentaires

1
votes

dans le schéma R5RS:

(define (average . numbers)  
    (/ (apply + numbers) (length numbers)))


0 commentaires