2009-09-05 4 views
2

Je suis un débutant à Scheme, alors pardonnez la question: J'ai une fonction qui calcule les factorielles d'une liste de nombres, mais cela me donne une période avant le dernier nombre dans le résultats. Où vais-je mal?Schéma Factoriel (fait * l) Question

code:

#lang scheme 

(define fact 
    (lambda (n) 
     (cond 
     ((= n 0) 1) 
     ((= n 1) 1) 
     (else (* n (fact (- n 1))))))) 

(define fact* 
    (lambda (l) 
    (cond 
     ((null? (cdr l)) (fact (car l))) 
     (else 
     (cons (fact (car l)) (fact* (cdr l))))))) 

sortie:

> (fact* '(3 6 7 2 4 5)) 
(6 720 5040 2 24 . 120) 

Répondre

8

Qu'est-ce que vous avez fait est de créer un improper list. Essayez ceci:

(define fact* 
    (lambda (l) 
    (cond 
     ((null? (cdr l)) (list (fact (car l)))) 
     (else 
     (cons (fact (car l)) (fact* (cdr l))))))) 

L'ajout du list dans la quatrième ligne devrait faire ce travail comme prévu. Mieux pourraient être les suivantes:

(define fact* 
    (lambda (l) 
    (cond 
     (null? l) '()) 
     (else 
     (cons (fact (car l)) (fact* (cdr l))))))) 

Cela permet à votre fonction fact* de travailler sur la liste vide, ainsi que la réduction du nombre d'endroits où vous faites un appel à fact.

+0

Merci! Existe-t-il un moyen de faire cela avec les primitives Scheme? Est-ce que la liste est une primitive? – Isaac

+1

J'ai modifié pour ajouter la deuxième mise en œuvre après votre commentaire ci-dessus. Est-ce que ça répond à votre question? –

+0

Ah, superbe! Ma connaissance du "Petit Schémer" a été oubliée momentanément. Je vous remercie! – Isaac

1

Utilisez append au lieu de cons. cons est utilisé pour construire des paires, c'est pourquoi vous avez le "." qui est utilisé pour séparer les éléments d'une paire. Voici un exemple:

(define (factorial n) 
    (if (<= n 1) 
     1 
     (* n (factorial (- n 1))))) 

(define (factorial-list l) 
    (if (null? l) 
     '() 
     (append (list (factorial (car l))) 
       (factorial-list (cdr l))))) 
+0

Pourriez-vous développer cela? Pourquoi exactement le "." être inséré dans ma liste quand je contre un atome sur une liste? – Isaac

+1

Une "paire" est un objet qui contient deux atomes. Une "liste" est une séquence de paires avec la propriété que le 'cdr' de chaque paire est une autre liste, à l'exception que la fin de la liste est indiquée par l'atome" liste vide ". Donc '(cons 'a (cons' b (cons 'c'())))' est une liste correcte, mais '(cons 'a (cons' b 'c))' est appelée une "liste incorrecte" parce que le 'cdr' de la deuxième contre n'est pas une liste. –

+1

Parce que dans votre dernière étape, vous construisez une paire composée d'une liste et d'un atome, par exemple '(cons '(20 21) 120)' => '((20 21). Pour le faire fonctionner correctement, vous devez convertir 120 en une liste. –

5

Les otheranswers ont souligné la raison pour laquelle vous obtenez une liste non conforme à la suite de votre fonction fact*. Je voudrais seulement souligner que vous pouvez utiliser le higher-order functionmap:

(define fact* 
    (lambda (l) 
    (map fact l)) 

(fact* '(3 6 7 2 4 5)) 

map prend une fonction et une liste comme arguments et applique la fonction à chaque élément de la liste, la production d'une nouvelle liste.