我在Dr. Racket工作,这是我第一次使用功能语言,所以我很困惑。
我只需要添加每种不同动物的重量"在列表中。 所有不同的动物都有一个体重"属性,但球拍不会让我访问"体重"任何给定列表元素的项目,因为它声称它未定义"
到目前为止我所拥有的:
(define (zoo-weight animals)
(cond [(empty? animals) 0]
[else (+ (first weight)(zoo-weight (rest animals)))])) ;This is where I get the error for weight, saying it is undefined.
如果有人可以让我知道如何引用体重而不管列表项目(蛇重,牛重等),这整个功能性的东西都会让人感到困惑。
谢谢!
答案 0 :(得分:1)
你几乎得到了它!尝试这样的事情:
(define (zoo-weight animals)
(cond [(empty? animals) 0]
[else (+ (weight (first animals))
(zoo-weight (rest animals)))]))
问题是你不能说(first weight)
。什么是weight
?它可能是适用于动物或变量的功能。所以,你写道:“取weight
的第一个元素”。显然,没有意义,我们想从列表中取出第一只动物,然后然后找出动物的体重,然后进入列表中的下一个动物。
如上所示,在你的程序中使用以下表达式,假设给我们动物体重的函数被称为weight
(如果没有,使用适当的函数 - animal-wight
,{ {1}},我不知道你怎么称呼它:
weight-animal
<强>更新强>
现在你提到每只动物都有不同的体重功能,我有几点评论。这是一个糟糕设计的症状,同样的功能应该适用于各种动物,以避免到处都是那些长条件(如果我们添加一种新的动物,这将是一个麻烦!)。我不知道这些动物目前是如何实施的,所以我无法提出进一步的建议。但如果无法修复当前表示,至少将条件封装在一个地方,如下所示:
(weight (first animals))
现在我的(define (weight animal)
; find the correct weight function
((cond ((snake? animal) snake-weight)
((dillo? animal) dillo-weight)
((ant? animal) ant-weight)
(else (error "Unknown animal:" animal)))
; apply the function to the animal
animal))
实现无需任何修改即可使用,无需在需要权重的地方复制条件。如果写一个以上的函数是一个问题(我无法想象为什么你的老师会提出这个限制,函数式编程鼓励构建大量可重用的函数!),我们总是可以插入代码:
zoo-weight
另外,借用@ Jack的解决方案,我们可以使用(define (zoo-weight animals)
(cond [(empty? animals) 0]
[else (+ (let ([animal (first animals)])
((cond ((snake? animal) snake-weight)
((dillo? animal) dillo-weight)
((ant? animal) ant-weight)
(else (error "Unknown animal:" animal)))
animal))
(zoo-weight (rest animals)))]))
(匿名函数)和高阶lambda
过程。这仍然算作一个单一的功能:
map
答案 1 :(得分:1)
假设你有一个动物列表和一个动物weight
,它需要一只动物并给你它的重量,你最好不要在这里使用apply
和map
代替自己做递归:
(define (zoo-weight animals)
(apply + (map weight animals)))
map
获取一个函数和一个列表,并为列表中的每个事物调用一次函数,例如(map sqrt '(9 16 25))
评估到列表'(3 4 5)
。 apply
函数接受一个函数和一个列表,并以列表项作为参数调用该函数,例如(apply + '(1 2 3))
与(+ 1 2 3)
相同。通过组合这两者,您可以获得所需的功能。从这些模式的角度来学习思考可能很困难,但是一旦你做到了,这样做的好处是巨大的。但是你应该首先深入理解Oscar Lopez的回答中的递归模式,这对于理解函数式编程模式是绝对必要的。
关于没有一般weight
函数和只允许创建一个的那一点就是限制。通常在函数式语言中,许多通用函数和辅助函数都是 good 。您可以使用Oscar答案中概述的匿名函数方法,但我想补充一点,使用zoo-weight
将此函数绑定到let
函数体中的名称可能会更好:
(define (zoo-weight animals)
(let ([weight (lambda (animal)
((cond [(snake? animal) snake-weight]
[(dillo? animal) dillo-weight]
[(ant? animal) ant-weight]
[else (error "Unknown animal:" animal)])
animal))])
(apply + (map weight animals)))
您也可以使用内部define
实现相同的目标:
(define (zoo-weight animals)
(define (weight animal)
((cond [(snake? animal) snake-weight]
[(dillo? animal) dillo-weight]
[(ant? animal) ant-weight]
[else (error "Unknown animal:" animal)])
animal))
(apply + (map weight animals)))
这与定义单独的辅助函数基本相同,但weight
函数隐藏在zoo-weight
函数内 - zoo-weight
函数外的任何代码都不能使用帮助器
正如约书亚所说,你可以使用其他更高阶的函数,例如foldl
的变体。 foldl
获取函数,初始值和列表,并使用步骤中的函数将列表缩减为一个值。 (foldl + 0 '(1 2 3))
与(foldl + 1 '(2 3))
相同,(foldl + 3 '(3))
与foldl
相同,为6.在Racket中,使用(apply + (map weight animals))
代替(foldl + 0 (map weight animals))
(foldl (lambda (animal acc) (+ acc (weight animal))) 0 animals)
看起来像这些中的任何一个:
(for/fold ([sum 0]) ([animal animals])
(+ sum (weight animal)))
Racket还提供了for/fold
宏,它可以使逻辑更清晰:
reduce
这个基于Common Lisp (define (reduce f xs #:key [key-func #f])
(let ([xs (if key-func (map key-func xs) xs)])
(foldl f (first xs) (rest xs))))
(reduce + animals #:key weight)
的折叠功能也适用:
{{1}}
答案 2 :(得分:0)
谢谢大家的回复,我放弃了你的时间投票。你的所有答案都很好,除了我只允许一个功能,所以我不能做出一个重量&#34;获得任何动物体重的功能。我最终不得不用一个大的&#34; cond&#34;声明如下。我知道这是不太好的代码,但它可以完成工作而无需构建任何其他功能(这是我唯一的选择):
(define (zoo-weight animals)
(cond [(empty? animals) 0]
[(snake? (first animals)) (+(snake-weight (first animals))(zoo-weight (rest animals)))]
[(dillo? (first animals)) (+(dillo-weight (first animals))(zoo-weight (rest animals)))]
[(ant? (first animals)) (+(ant-weight (first animals))(zoo-weight (rest animals)))]
))
再次感谢,您的所有答案都帮助我来到这里!