2013-04-30 63 views
1

我是新来的函数式编程,并试图写一个函数,它接受一个列表参数,如果列表包含每个符号的长度为1的更具体的符号返回true,如何确定输入是否是计划中的序列?

;(sequence? '(a b c)) ----> true 
; (sequence? '(aa b c)) ---> false since aa has length 2 
; (sequence? '(a 1 c)) ----> false since 1 is not a symbol 
; (sequence? '(a (b c))) --> false since (b c) is not a symbol 

我的想法执行以下操作:对于列表中的每个符号,我检查它是否是一个符号,它是长度为1

(define sequence? 
     (lambda (inSeq) 
     (if (for each item in the list inSeq, all are symbols and length=1) #t #f) 

    ) 
) 

的然后根据结果,我返回真或假。但我不知道如何迭代列表。我不想将列表转换为字符串并使用字符串函数。我们是否有像“foreach”这样的语句,或循环做我的想法?或任何其他建议?

注意:我也考虑过使用汽车,然后将其取下并查看列表的其余部分,但由于我不知道长度,我不知道应该使用汽车多少次,即是否它应该是汽车,CAAR,caaar等

谢谢

回答

2

如果你已经解决了该列表的第一个元素的问题,那么你已经解决了它在列表的其余元件只是重新应用相同的过程中休息。

对于需要进行如下的第一个元素:

(define (is-symbol-1 thing) 
    (and (symbol? thing) 
     (= 1 (string-length (symbol->string thing)))) 

然后

(define (sequence? list) 
    (or (null? list)      ;; #t if list is empty 
     (and (is-symbol-1 (car list)) ;; first element is-symbol-1 
      (sequence? (cdr list))))) ;; and rest is sequence? too 

这是递归的一个例子。在您学习Scheme时,您将通过寻找利用递归的机会获益。

+1

谢谢!我不知道如何使用递归,现在我明白了 – yrazlik 2013-04-30 17:34:51

2

首先,让我们弄清楚一个拉姆达将返回true,当它的参数是一个长度的象征,否则为false:

(λ (x) (and (symbol? x) (= (string-length (symbol->string x)) 1))) 

;; 'a -> #t, 'aa -> #f, '(a) -> #f 

我们不得不在那里使用字符串函数,因为有n o符号'f和符号'foo之间的有意义的区别,除了它们的字符串表示形式。

现在,让我们采取的拉姆达,并用它来过滤从我们的名单坏分子:

(filter (λ (x) (and (symbol? x) (= (string-length (symbol->string x)) 1))) 
     '(a b c)) 

;; '(a b c) -> '(a b c), '(a 2 c) -> '(a c), '(a bb c) -> '(a c) 

现在,让我们检查,以确保没有被过滤掉,也就是我们原来的列表中的每一个元素是一个长度为1的符号。我们通过检查输出列表的长度与输入列表的长度是否相同来做到这一点。

(define (symbols-of-length-1 seq) 
    (= (length (filter (λ (x) (and (symbol? x) (= (string-length (symbol->string x)) 1))) 
      seq)) 
    (length seq))) 

;; '(a b c) -> #t, '(a 2 c) -> #f, '(a (b) c) -> #f, '(a bb c) -> #f 
+0

感谢您的回答! – yrazlik 2013-04-30 17:36:38

2

我们有像“的foreach”,或循环做什么,我想任何声明?

或任何其他建议?

遍历在计划列表中,你要么使用迭代列表(如mapfilterfold-left)预先存在的功能或者你写你自己使用递归。根据您使用的Scheme方言,可能已经有一个函数(称为everyandmap),它接受一个列表和一个条件,并且如果列表中的每个条目的条件为真,则返回#t。否则,你不得不递归地写成它或作为一个折叠(尽管并非所有Scheme方言都具有折叠功能)。

递归函数,在一个列表上循环通常看起来是这样的:

(define (do-something-with-list lst) 
    (if (null? lst) 
    (handle-the-case-that-list-is-empty) 
    (combine 
     (some-transformation-on (car lst)) 
     (do-something-with-list (cdr lst))))) 

例如总结在大于5列表中的所有号码(不使用filterfold-left),你会写:

(define (sum-all-numbers>5 numbers) 
    (if (null? numbers) 
    ; Sum of the empty list is 0 
    0 
    (+ 
     ; If the head of the list is > 5, add the number to the result, else 
     ; add 0 
     (if (> (car numbers) 5) (car numbers) 0) 
     (sum-all-numbers>5 (cdr numbers))))) 

您可以使用相同的方法来定义您的功能。

PS:(if condition #t #f)是多余的 - 你可以只写condition(除非condition比其他布尔值的东西,你需要将其转换成一个布尔值,但我不能想象一个场景的地方是会是必要的)。

+0

感谢您的回答! – yrazlik 2013-04-30 17:35:31

2

一个简单的方法,使用容易获得的功能 - 特别是,可以(在SRFI-1或在R6RS for-all,或every)使用在球拍andmap;将其视为foreach如果列表中的所有元素都满足谓词,则返回#t。该解决方案更符合功能编程的精神,因为它使用通用的高阶程序,通过将现有解决方案与其他子问题相结合来解决新问题。换句话说,我们不重新发明轮子:

(define (sequence? seq)  ; `seq` is a sequence if 
    (andmap (lambda (e)  ; it's true for all its elements that 
      (and (symbol? e) ; each element is a symbol 
       (= 1 (string-length (symbol->string e))))) ; with length one 
      seq)) 

注意代码如何说,到底是什么意思:一个列表是一个“序列”如果这是真的,它的所有元素,每一个是一个长度的象征。为了确定一个符号的长度,我们首先将它转换成一个字符串,我们可以很容易地检查它是否符合长度要求。它按预期工作:

(sequence? '(a b c)) 
=> #t 
(sequence? '(aa b c)) 
=> #f 
(sequence? '(a 1 c)) 
=> #f 
(sequence? '(a (b c))) 
=> #f 
+1

如果你的Scheme有它,你只能重用它:) R6RS别名是'for-all' – leppie 2013-04-30 15:12:33

+1

也像@ sepp2k在SRFI-1中说'every' :) http://srfi.schemers.org/srfi-1/ srfi-1.html#正在搜索 – leppie 2013-04-30 16:16:52

+0

确定,已更新;-) – 2013-04-30 16:22:03

相关问题