当我尝试使用下面的函数来实现类似下面的函数时,编译器返回
解析错误(可能是错误的缩进或括号不匹配)
功能:
demo 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)
我该如何纠正? 此致!
答案 0 :(得分:3)
您无法在顶层写let n = 0
。删除后,代码的else let
部分也没有正确缩进,因为它的使用(do
块之外)总是let ... in ...
,而let
的内容也是let
的内容1}}部分必须同样缩进。即使格式化,arg = arg - 1
也是递归的,因此demo n xs = take n (cycle xs)
表示比自身少一个的值,它不会计算。
现在,这个函数实际上做了两件事:它循环遍历列表的所有元素,并且还将它限制为给定的长度。这些都已在标准库中提供。
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
如果您想自己编写,类似的细分也是合理的。
length
请注意,没有必要使用length
,这是一件好事!
app_1 | bundler: command not found: puma
app_1 | Install missing gem executables with
在无限列表上有所不同,而这会优雅地处理它们。bundle install
ibuy7_db_backup_1 exited with code 0
ibuy7_app_1 exited with code 127
答案 1 :(得分:2)
您正在混合命令式和功能性范例:let n = 0
,let (x:xs) = (x:xs) ++ (x:xs)!!n
,arg = arg - 1
,n = n + 1
(在您的代码中)是命令式表达式。您希望修改n
,(x:xs)
和arg
的值,但功能编程不会像那样工作。
您声明的功能是纯:这意味着您不能期望值被修改(我们称之为&#34;副作用&#34;) 。你唯一能做的就是用一个新的参数来调用一个新的函数(或相同的函数),这些参数是在运行中随时计算的#34;来自原始论点。
让我们尝试具体。
你无法做到:
arg = arg - 1
demo arg (x:xs)
但你可以这样做:
demo (arg - 1) (x:xs)
后者是demo
的调用,arg - 1
为参数。 arg
的值从未被修改过。
代码中的主要问题是n
变量。首次调用时应为0
,并且每次arg < length (x:xs)
都应增加(x:xs)
中的下一个元素到(x:xs)
本身的末尾。因此,列表将以循环方式增长,直到我们可以获取所需数量的元素。
要达到这个目标,你必须创建一个辅助功能,然后移动&#34;递归到辅助函数:
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]) ```
现在,从您给出的示例中,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])
有一种更好的方法可以实现这一目标(demo n=take n.cycle
),但我试图接近原来的实现。