Functional programming 如何确定输入是否为方案中的序列?

Functional programming 如何确定输入是否为方案中的序列?,functional-programming,scheme,Functional Programming,Scheme,我不熟悉函数式编程,并且尝试编写一个函数,该函数接受一个列表参数,如果列表由符号组成,且每个符号的长度为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)))

我不熟悉函数式编程,并且尝试编写一个函数,该函数接受一个列表参数,如果列表由符号组成,且每个符号的长度为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”或for循环这样的语句来实现我的想法?还有其他建议吗

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


谢谢

首先,让我们计算一个lambda,当它的参数是长度为1的符号时,它将返回true,否则返回false:

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

;; 'a -> #t, 'aa -> #f, '(a) -> #f
我们必须在那里使用字符串函数,因为符号
'f
和符号
'foo
之间没有有意义的区别,除了它们的字符串表示形式

现在,让我们以lambda为例,用它从列表中筛选出不好的元素:

(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

首先,让我们计算一个lambda,当它的参数是长度为1的符号时,它将返回true,否则返回false:

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

;; 'a -> #t, 'aa -> #f, '(a) -> #f
我们必须在那里使用字符串函数,因为符号
'f
和符号
'foo
之间没有有意义的区别,除了它们的字符串表示形式

现在,让我们以lambda为例,用它从列表中筛选出不好的元素:

(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
我们有没有像“foreach”或for循环这样的语句来实现我的想法

没有

还有其他建议吗

要在scheme中迭代列表,您可以使用预先存在的函数来迭代列表(如
map
filter
fold left
),也可以使用递归编写自己的函数。根据您使用的方案方言,可能已经有一个函数(称为
each
和map
)接受列表和条件,并在列表中的每个项目的条件为真时返回
#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的所有数字求和(不使用
过滤器
左折
),您可以编写:

(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:
(如果条件#t#f)
是多余的——您可以只编写
条件
(除非
条件
不是布尔值,您需要将其转换为布尔值,但我想不出有必要这样做的场景)

我们有没有像“foreach”或for循环这样的语句来实现我的想法

没有

还有其他建议吗

要在scheme中迭代列表,您可以使用预先存在的函数来迭代列表(如
map
filter
fold left
),也可以使用递归编写自己的函数。根据您使用的方案方言,可能已经有一个函数(称为
each
和map
)接受列表和条件,并在列表中的每个项目的条件为真时返回
#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的所有数字求和(不使用
过滤器
左折
),您可以编写:

(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:
(如果条件#t#f)
是多余的——你可以只写
条件
(除非
条件
不是布尔值,你需要将它转换成布尔值,但我想不出有必要的场景)。

一种简单的方法,使用现成的函数——特别是,您可以在球拍中使用(或在R6RS中,或在SRFI-1中使用);可以将其视为一个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))
请注意代码是如何准确表达其含义的:如果列表的所有元素都是长度为1的符号,那么列表就是一个“序列”。为了确定一个符号的长度,我们首先将它转换成一个字符串,我们可以很容易地检查它是否满足长度要求。它按预期工作:

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

一种简单的方法,使用现成的功能-特别是,您可以在Racket(或R6RS,或SRFI-1)中使用;可以将其视为一个foreach,如果列表中的所有元素都满足一个谓词,它将返回
#t
。此解决方案更符合函数式编程的精神,因为它使用通用的高阶过程通过结合现有解决方案来解决新问题