2017-09-11 1 views
0

Je suis en train d'évaluer chaque atome d'une liste et de voir si elle est égale au nombre prévu et retirer si son pas, mais je suis en cours d'exécution dans un léger problème.LISP ne peut pas prendre la voiture de T

j'ai écrit le code suivant:

(defun equal1(V L) 
    (cond((= (length L) 0)) 
      (T (cond((not(= V (car(equal1 V (cdr L))))) (cdr L)))) 
    ) 
) 

(equal1 5 '(1 2 3 4 5)) 

J'obtiens l'erreur suivante

Error: Cannot take CAR of T. 

Si j'ajoute (écrire "bonjour") pour l'action si elle est vraie, l'erreur suivante est obtenue: Je suis encore un peu nouveau à LISP et je me demandais ce qui se passe exactement et comment pourrais-je f ix ceci afin que je puisse évaluer chaque atome correctement et l'enlever s'il n'est pas, ainsi le cdr L pour l'action.

+0

Quelle variété de Lisp est-ce? – user2357112

+0

Je ne suis pas sûr mais d'après ce que j'ai vu, c'est comme le générique auquel nous n'utilisons que cond. –

+0

Son tout ce que je reçois de Lisp fonctionne édition personnelle –

Répondre

1

Il y a quelques choses que vous pouvez faire pour améliorer cette fonction.

Tout d'abord, nous allons indentent correctement

(defun equal1 (V L) 
    (cond 
    ((= (length L) 0)) 
    (T (cond 
     ((not (= V (car (equal1 V (cdr L))))) (cdr L)))))) 

Plutôt que de dire (= (length l) 0), vous pouvez utiliser (zerop (length l)). Un point sylistique mineur. Pire, cette branche ne renvoie aucune valeur. Si la liste L est vide, que devrions-nous retourner?

Le problème avec la fonction se trouve dans la branche T du premier cond.

Ce que nous voulons faire est

  1. supprimer tout élément de la liste qui est la même valeur que V
  2. garder tout élément qui ne = à V

La fonction doit renvoyer une liste.

L'expression

(cond 
    ((not (= V (car (equal1 V (cdr L))))) (cdr L))) 

tente (je pense) pour traiter les conditions 1 et 2. Toutefois, il est clairement ne fonctionne pas.

Nous devons rappeler que les éléments sont dans une liste et que le résultat de la fonction égale doit être une liste. Dans l'expression ci-dessus, le résultat de la fonction sera un booléen et donc le résultat de l'appel de la fonction sera booléen.

La fonction doit parcourir chaque élément de la liste et lorsqu'elle voit une valeur correspondante, ignorez-la, sinon utilisez la fonction contre pour générer la liste de sortie filtrée.

Voici un squelette pour vous aider. Notez que nous n'avons pas besoin du cond intégré et que nous avons juste 3 conditions à traiter - liste vide, filtre une valeur, ou continue à construire la liste.

(defun equal-2 (v l) 
    (cond 
    ((zerop (length L)) nil) 
    ((= v (car l)) <something goes here>)  ;skip or filter the value 
    (t (cons (car l) <something goes here>)))) ;build the output list 

Bien sûr, étant Common Lisp, il existe une fonction intégrée qui fait cela. Vous pouvez regarder dans remove-if ...

+0

Ah donc il semble que le bloc serait la fonction d'appel récursif de v et cdr l pour garder la descente jusqu'à la première si le bloc est satisfait –

+0

Ce serait correct –

2

car et cdr sont des accesseurs d'objets de type cons. Depuis t et "hello" ne sont pas cons vous obtenez un message d'erreur.

Pour résoudre ce problème, vous devez savoir quels types vos retours de fonction et non car sauf si vous savez que c'est un cons

EDIT

Tout d'abord ident et nettoyer le code .. Le cond imbriquée sont uneccesary depuis cond est un si-elseif-else Structure par défaut:

(defun remove-number (number list) 
    (cond ((= (length list) 0) 
     t) 
     ((not (= number (car (remove-number number (cdr list))))) 
     (cdr list)))) 
     (t 
     nil))) 

Je veux que vous remarquiez que j'ai ajouté le comportement par défaut de retourner t quand un conséquent n'est pas donné comme nous le savons = renvoie t ou nil alors il renvoie t lorsque la longueur est 0 dans ce cas.

J'ai ajouté le cas par défaut où aucune des deux prédicats précédentes étaient truthy et il est par défaut à retourner nil.

J'ai nommaient selon les fonctions utilisées. = ne peut être utilisé que pour les arguments numériques et donc ne fonctionnera jamais sur les symboles, les chaînes, etc. Vous devez utiliser equal si vous étiez après des valeurs qui se ressemblent.

En regardant ce maintenant nous pouvons voir que les fonctions renvoient la valeur est pas très facile à raisonner. Nous savons que t, nil et list ou toute partie de la queue de list sont possibles et ainsi faire car pourrait ne pas fonctionner ou dans le cas de (car nil) il peut ne pas produire un nombre.

Une meilleure approche pour y parvenir serait:

  1. vérifier si la liste est vide, puis revenez nil
  2. vérifier si le premier élément a la même valeur numérique que number, récursif puis avec le reste la liste (ignorer l'élément)
  3. par défaut devrait faire cons une liste avec le premier élément et le résultat de la récursion avec le reste de la liste.

Le code ressemblerait à quelque chose comme ceci:

(defun remove-number (number list) 
    (cond ((endp list) '()) 
     ((= (car list) number) (remove-number ...)) 
     (t (cons ...)))) 
+0

Comment aurais-je voiture et cdr accéder à la liste et pas t ou bonjour, je ne sais pas pourquoi y accéder ces deux im encore tout à fait nouveau à lisp –

+0

wouldnt la récursion s'arrêter instantanément si la première valeur dans la liste n'est pas égale à la valeur Ainsi, toute la liste ne serait pas évaluée? –

+0

@KyleJ Le deuxième et le troisième terme font la même récursivité, seulement que le troisième fait comme second argument de «cons» pour avoir le reste de la liste incluant le premier élément alors que le second terme ne fait pas ça puisque l'élément en cours ne doit pas être inclus. – Sylwester