在函数中使用函数

时间:2020-09-26 02:46:44

标签: racket

我有一个名为clean-up的函数,它基本上可以完成已经可用的flatten函数的工作。然后,我有了一个名为multiplier的函数,该函数接收一个列表并将其中的所有数字相乘。一个问题是,有时multiplier中使用的列表可能会有一种奇怪的语法,并且它不会将每个数字相乘。例如:

示例输入

(multiplier '((1 (2 3)) 4 5 (6)))

正确的输出

720

我的输出

*: contract violation
  expected: number?
  given: '(6 . 1)
  argument position: 2nd
  other arguments...

我们现在不喜欢错误吗?此multiplier函数可用于外观正常的列表,例如(multiplier '(1 2 3 4 5 6))。因此,我编写了clean-up函数,将一些令人困惑的列表变成了正常外观的列表。但是,在尝试解析并进行乘法运算之前,我不知道如何调用它来清理列表。我可以验证clean-up函数是否能很好地完成其工作。有人可以帮忙吗?这是我两个人的代码:

(define (clean-up s)
  (cond [(null? s) '()]
        [(not (pair? s)) (list s)]
        [else (append (clean-up (car s)) (clean-up (cdr s)))]
))

(define multiplier
  (lambda (s)
    (cond [(null? s) 1]
          [(number? (car s)) (* (car s) (multiplier(cdr s)))]
          [list? (car s) (append (car s) (multiplier(cdr s)))]
          [else (multiplier (cdr s))]
)))

2 个答案:

答案 0 :(得分:1)

不需要clean-up函数来解决multiplier中遇到的问题。但是,您可以首先使用以下命令在输入上调用clean-up

scratch.rkt> (multiplier (clean-up '((1 (2 3)) 4 5 (6))))
720

或者,您可以创建一个辅助函数来为您执行此操作:

(define (multiplier-workaround s)
  (multiplier (clean-up s)))
scratch.rkt> (multiplier-workaround '((1 (2 3)) 4 5 (6)))
720

类似的解决方法可能会在一定程度上帮助您,但不能解决代码中的实际问题。

使用更好的代码格式可能更容易发现此处的某些问题。在Lisps中留下吊括号是 bad 样式,就像这些是C样式语言一样。但这可能不会给您造成问题。但是,使用缩进来显示表达式的结构是样式。通过适当的缩进,很明显list?谓词行中缺少括号:

(define multiplier
  (lambda (s)
    (cond [(null? s) 1]
          [(number? (car s))
           (* (car s) (multiplier(cdr s)))]
          [list? (car s)
                 (append (car s) (multiplier (cdr s)))]
          [else
           (multiplier (cdr s))])))

对该行的进一步调查显示,代码正在尝试将(car s)附加到(multiplier (cdr s))的结果中;然而,现在已知(car s)是一个列表,而multiplier应该返回一个数字!这里的意图肯定是要与列表multiply上的调用(car s)的结果与(multiplier (cdr s))的结果相乘

(define multiplier
  (lambda (s)
    (cond [(null? s) 1]
          [(number? (car s))
           (* (car s)
              (multiplier (cdr s)))]
          [(list? (car s))
           (* (multiplier (car s))
              (multiplier (cdr s)))]
          [else
           (multiplier (cdr s))])))

不清楚为什么需要else分支,除非OP希望能够处理诸如(a (1 (2 b) (3 (c (4 5) 6) d) e)))之类的列表。对于期望嵌套数字列表的代码,可以这样做:

(define multiplier-2
  (lambda (s)
    (cond [(null? s) 1]
          [(number? (car s))
           (* (car s) (multiplier (cdr s)))]
          [else
           (* (multiplier (car s))
              (multiplier (cdr s)))])))

这两个函数现在都可以用于OP示例表达式,并且更正后的OP代码也可以用于带有虚假值的输入:

scratch.rkt> (multiplier '((1 (2 3)) 4 5 (6)))
720
scratch.rkt> (multiplier-2 '((1 (2 3)) 4 5 (6)))
720
scratch.rkt> (multiplier '(a (1 (2 3)) 4 5 b (6) c))
720

答案 1 :(得分:0)

我认为内置flatten的错误处理更多。

(define (multiplier lst)
  (apply * (filter number? (flatten lst))))

;;; TEST
(define test-lst1 (list + (vector 1) '(1 (2 3) c) "w" 4 5 '(6) + - * sqr))
(define test-lst2 '(1(a 2(3 b (c 4(d 5 e(6) (f)))))))
(multiplier test-lst1) ; 720
(multiplier test-lst2) ; 720
相关问题