Haskell新手问题:是否有一种技术可以提高效率并避免对tail原始列表进行两次调用
func1 originalList =
func2 (doSomething (tail originalList)) (doSomethingDifferent (tail originalList))
doSomething listA =
....
doSomethingDifferent listB =
....
func2 listA listB =
....
答案 0 :(得分:9)
在命令式编程语言中,您只需调用该函数一次,并将其存储到变量中。
在像Haskell这样的函数式编程语言中,您使用where
或let
子句,因此也使用变量:
func1 originalList = func2 (doSomething t) (doSomethingDifferent t)
where t = tail originalList
所以在这里你将构造一个表达式,doSomething
和doSomethingDifferent
的参数将引用到同一个表达式树。现在,因为Haskell工作 lazily tail originalList
将不立即进行评估。
但是如果它(部分)被评估(例如在评估func2
调用的第一个操作数时),那么当通过另一种方式计算表达式树时,该工作是而不是重做(例如第二个参数)。现在在tail
的情况下,无论如何都没有多少工作。但如果它是一个更复杂的功能,它会带来更多回报。
请注意 - 如@amalloy says - 如果是tail
函数,则不必使用where子句:简单模式匹配就足够了:
func1 (_:t) = func2 (doSomething t) (doSomethingDifferent t)
请注意,这两者并不完全等效:因为现在有一个约束,如果你有一个至少包含一个元素的列表,该行只会触发。有可能func2
只是忽略了两个参数,因此不需要获得尾部(虽然这不太可能)。