2009-09-05 2 views
2

Я новичок на Схеме, поэтому простите вопрос: у меня есть функция, которая вычисляет факториалы списка чисел, но это дает мне период до последнего числа в Результаты. Где я иду не так?Схема факториала (факт * l) Вопрос

код:

#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))))))) 

выход:

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

ответ

8

То, что вы сделали это создать improper list. Попробуйте это:

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

Добавление list в четвертой строке должны сделать эту работу, как вы ожидаете. Лучше может быть следующим:

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

Это позволяет вашей fact* функции работать на пустом список, а также сокращение количества мест, где вы делаете вызов fact.

+0

Спасибо! Есть ли способ сделать это с помощью примитивов Scheme? Является ли список примитивным? – Isaac

+1

Я отредактировал, чтобы добавить вторую реализацию после вашего комментария выше. Отвечает ли это на ваш вопрос? –

+0

А, отлично! Знание «Маленького Schemer» было забыто на мгновение. Спасибо! – Isaac

1

Использовать append вместо cons. cons используется для построения пар, поэтому у вас есть «.». который используется для разделения элементов пары. Вот пример:

(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

Не могли бы вы рассказать об этом? Почему именно «.» войти в мой список, когда я задерживаю атом в списке? – Isaac

+1

«Пара» - это объект, содержащий два атома. «Список» представляет собой последовательность пар с тем свойством, что 'cdr' каждой пары является другим списком, за исключением того, что конец списка обозначается атомом« пустой список ». Поэтому '(cons 'a (cons' b (cons 'c'())))' является правильным списком, но '(cons 'a (cons' b 'c))' называется "неправильным списком", потому что 'cdr' вторых минусов не является списком. –

+1

Поскольку на последнем этапе вы создаете пару, состоящую из списка и атома, например '' (cons '(20 21) 120) '=>' ((20 21). 120) '. Чтобы он работал правильно, вам нужно преобразовать 120 в список. –

5

otheranswers указал причину, почему вы получаете ненадлежащей список в результате вашей fact* функции. Я хотел бы только отметить, что вы могли бы использовать higher-order functionmap:

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

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

map принимает функцию и список в качестве аргументов и применяет функцию к каждому элементу в списке, создавая новый список.

Смежные вопросы