如何避免两次进行函数调用?

时间:2017-06-23 11:07:04

标签: haskell

Haskell新手问题:是否有一种技术可以提高效率并避免对tail原始列表进行两次调用

func1 originalList =
    func2 (doSomething (tail originalList)) (doSomethingDifferent (tail originalList))

doSomething listA =
....

doSomethingDifferent listB =
....

func2 listA listB =
....

1 个答案:

答案 0 :(得分:9)

命令式编程语言中,您只需调用该函数一次,并将其存储到变量中。

在像Haskell这样的函数式编程语言中,您使用wherelet子句,因此也使用变量:

func1 originalList = func2 (doSomething t) (doSomethingDifferent t)
    where t = tail originalList

所以在这里你将构造一个表达式,doSomethingdoSomethingDifferent的参数将引用到同一个表达式树。现在,因为Haskell工作 lazily tail originalList立即进行评估。

但是如果它(部分)被评估(例如在评估func2调用的第一个操作数时),那么当通过另一种方式计算表达式树时,该工作是而不是重做(例如第二个参数)。现在在tail的情况下,无论如何都没有多少工作。但如果它是一个更复杂的功能,它会带来更多回报。

请注意 - 如@amalloy says - 如果是tail函数,则不必使用where子句:简单模式匹配就足够了:

func1 (_:t) = func2 (doSomething t) (doSomethingDifferent t)

请注意,这两者并不完全等效:因为现在有一个约束,如果你有一个至少包含一个元素的列表,该行只会触发。有可能func2只是忽略了两个参数,因此不需要获得尾部(虽然这不太可能)。