我们如何限制 Haskell 中的递归调用?

Tim*_*tzy 5 recursion haskell

我的代码有问题,如下所示:

import Data.List

splitat _ [] = ([],[])
splitat element (head:tail)
  | element == head = ([],(head:tail))
  | otherwise = ([head]++fst(splitat element tail), snd(splitat element tail))
Run Code Online (Sandbox Code Playgroud)

它在“元素”处拆分列表,然后将左右子列表组合成一个元组。然而,在第三行中,'splitat element tail' 命令被调用两次,一次通过'fst',一次通过'snd'。有没有办法只评估这个术语 1 次以保持递归树的狭窄?

提前致谢。

Wil*_*sem 7

是的。您可以使用let表达式或where子句。例如:

splitat :: Eq a => a -> [a] -> ([a], [a])
splitat _ [] = ([],[])
splitat x' xa@(x:xs) | x == x' = ([], xa)
                     | otherwise = (x:ys1, ys2)
    where (ys1, ys2) = splitat x' xs
Run Code Online (Sandbox Code Playgroud)

:请不要使用head :: [a] -> atail :: [a] -> [a]或者被定义为变量,因为这些东西会等功能影子现有的结合。这使得对代码进行推理变得更加困难,因为人们可能会认为headtail引用这些函数,而不是变量。

  • 尽管可以说,如果从“base”和所有使用它们的库中清除“head”和“tail”会更好...... (3认同)

che*_*ner 5

使用Control.Arrow.first(或Data.Bifunctor.first; 该arrow库随 GHC 一起提供,而我不记得您是否需要先安装bifunctor):

splitat _ [] = ([],[])
splitAt e lst@(h:t) | e == h = ([], lst)
                    | otherwise = first (h:) (splitAt e t)
Run Code Online (Sandbox Code Playgroud)

  • [`Data.Bifunctor`](https://hackage.haskell.org/package/base-4.12.0.0/docs/Data-Bifunctor.html) 现在位于 `base` 中;如果我正确地阅读了我的版本号(“base”4.8.0.0),它是在 GHC 7.10 中添加的。 (3认同)