当我尝试使用下面的函数来实现像下面这样的函数时,编译器返回
解析错误(可能不正确的缩进或不匹配的括号)
功能:
演示 8 [1,2,3] 应该返回 [1,2,3,1,2,3,1,2]
demo :: Int -> [a] -> [a]
let n = 0
demo arg [] = []
demo arg (x:xs) =
if arg <= length (x:xs) then
take arg (x:xs)
else
let (x:xs) = (x:xs) ++ (x:xs)!!n
arg = arg - 1
n = n + 1
demo arg (x:xs)
Run Code Online (Sandbox Code Playgroud)
我该如何纠正?问候!
您正在混合命令式和函数式范式:let n = 0
, let (x:xs) = (x:xs) ++ (x:xs)!!n
, arg = arg - 1
,n = n + 1
是(在您的代码中)命令式表达式。您希望n
,(x:xs)
和的值arg
被修改,但函数式编程并不是这样工作的。
您声明的函数是纯函数:这意味着您不能期望值被修改(我们称之为“副作用”)。您唯一可以做的就是使用从原始参数“动态”计算的新参数调用新函数(或相同函数)。
让我们试着具体一点。
你不能这样做:
arg = arg - 1
demo arg (x:xs)
Run Code Online (Sandbox Code Playgroud)
但你可以这样做:
demo (arg - 1) (x:xs)
Run Code Online (Sandbox Code Playgroud)
后者是demo
witharg - 1
作为参数的调用。的值arg
从未被修改。
您代码中的主要问题是n
变量。它应该是0
第一次调用,并且每次都应该增加arg < length (x:xs)
以将下一个元素添加(x:xs)
到(x:xs)
自身的末尾。因此,列表将以循环方式增长,直到我们可以获取所需数量的元素。
为了达到这个目标,你必须创建一个辅助函数并将递归“移动”到该辅助函数中:
demo :: Int -> [a] -> [a]
demo arg [] = []
demo arg (x:xs) = demo' arg 0 (x:xs) -- n = 0
where
demo' :: Int -> Int -> [a] -> [a]
demo' arg n l = if arg <= length l
then take arg l
else
-- call demo' with new parameters:
-- (x:xs) = (x:xs) ++ [(x:xs)!!n]
-- arg = arg - 1
-- n = n + 1
demo' (arg-1) (n+1) ((x:xs) ++ [(x:xs)!!n]) ```
Run Code Online (Sandbox Code Playgroud)
现在,根据您给出的示例,arg
您要创建的列表中的元素数量是常数,因此不应减少。而且您不需要解构(x:xs)
. 最后,稍微清理一下,你有:
demo :: Int -> [a] -> [a]
demo arg [] = []
demo arg l = demo' arg 0 l
where
demo' :: Int -> Int -> [a] -> [a]
demo' arg n l = if arg <= length l
then take arg l
else demo' arg (n+1) (l ++ [l!!n])
Run Code Online (Sandbox Code Playgroud)
有一个更好的方法来实现这一点 ( demo n=take n.cycle
),但我试图接近你的原始实现。
你不能写let n = 0
在顶层。一旦删除它,else let
代码的该部分也不会正确缩进,因为它的使用(在块之外do
)总是let ... in ...
,并且该部分的内容let
必须同样缩进。即使它被格式化,let
也是递归的,所以arg = arg - 1
意味着一个值比它本身小一,这不能计算。
现在,这个函数实际上做了两件事:循环遍历列表的所有元素,并将其限制为给定的长度。这两个都已经在标准库中可用。
demo n xs = take n (cycle xs)
Run Code Online (Sandbox Code Playgroud)
如果你想自己写的话,类似的细分也是合理的。
demo :: Int -> [a] -> [a]
-- Handle negative n, so we can assume it's positive below
demo n _ | n < 0 = []
-- Similarly, handle empty list, so we can assume it's non-empty below
demo _ [] = []
-- Given a positive n and non-empty list, start cycling list with limit n.
demo n list = demo' n list
where
-- Limit has been reached, stop.
demo' 0 _ = []
-- List is exhausted, cycle back to the start.
demo' m [] = demo' m list
-- Take the next element of the list and continue.
demo' m (x:xs) = x : demo' (m-1) xs
Run Code Online (Sandbox Code Playgroud)
请注意,没有必要使用length
,这是一件好事!length
在无限列表上发散,而这可以优雅地处理它们。
归档时间: |
|
查看次数: |
11100 次 |
最近记录: |