我的代码有问题,如下所示:
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 次以保持递归树的狭窄?
提前致谢。
是的。您可以使用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] -> a
或tail :: [a] -> [a]
或者被定义为变量,因为这些东西会等功能影子现有的结合。这使得对代码进行推理变得更加困难,因为人们可能会认为head
并tail
引用这些函数,而不是变量。
使用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)