Haskell:分析错误可能是缩进不正确或括号不匹配
当我尝试使用下面的函数来实现下面的函数时,编译器返回 分析错误(可能缩进不正确或括号不匹配) 职能:Haskell:分析错误可能是缩进不正确或括号不匹配,haskell,Haskell,当我尝试使用下面的函数来实现下面的函数时,编译器返回 分析错误(可能缩进不正确或括号不匹配) 职能: 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 <= leng
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]) ```
演示8[1,2,3]应返回[1,2,3,1,2,3,1,2]
demo::Int->[a]->[a]
设n=0
演示参数[]=[]
演示参数(x:xs)=
如果arg您无法在顶层写入让n=0
。一旦删除它,代码的else let
部分也不会正确缩进,因为它的用法(在do
块之外)总是let。。。在…
中,let
部分的内容必须相等缩进。即使它是格式化的,let
也是递归的,因此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
demo::Int->[a]->[a]
--处理负n,所以我们可以假设它在下面是正的
演示n | n<0=[]
--类似地,处理空列表,所以我们可以假设它在下面是非空的
演示[]=[]
--给定一个正n和非空列表,开始循环限制为n的列表。
演示n列表=演示n列表
哪里
--已达到极限,停止。
演示“0”
--列表已用尽,循环回到开始。
演示'm[]=演示'm列表
--获取列表中的下一个元素并继续。
演示'm(x:xs)=x:demo'(m-1)xs
请注意,不必使用长度
,这是一件好事<代码>长度
在无限列表上发散,而这将优雅地处理它们。您正在混合命令式和函数式范例: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)
但你可以做到:
demo (arg - 1) (x:xs)
后者是调用demo
,参数为arg-1
。从未修改过arg
的值
代码中的主要问题是n
变量。它在第一次调用时应该是0
,并且应该在每次arg
时增加,以将(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]) ```
有一种更好的方法来实现这一点(
demo n=take n.cycle
),但我试图保持与原始实现接近。可能存在不正确的缩进。let..in
块看起来缩进不正确。尝试对其缩进进行实验,以获得要编译的代码。let arg=arg-1
和let n=n+1
是递归定义,它们将arg
和n
定义为无限循环计算。你不会想要的。您正在尝试在Haskell中对变量进行变异,而Haskell的设计就是为了让这变得不可能。这种方法在FP语言中太过必要。粗略地说,“更改”变量的唯一方法是使用新值调用函数,例如f0=0;fn=f(n-1)
定义了一个递归,它“减少”n
直到它达到0。谢谢jferard!你的代码正是我的意思。我认为问题是由变量n引起的,但我不知道如何解决,谢谢你回答我的问题。@Sean,不客气。你要么接受我的答案,要么接受伊弗米特的答案。
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])