Haskell:解析错误可能是错误的缩进或括号不匹配

时间:2017-08-13 06:46:30

标签: haskell

当我尝试使用下面的函数来实现类似下面的函数时,编译器返回

  

解析错误(可能是错误的缩进或括号不匹配)

功能:

  

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)

我该如何纠正? 此致!

2 个答案:

答案 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 = 0let (x:xs) = (x:xs) ++ (x:xs)!!narg = arg - 1n = 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),但我试图接近原来的实现。

相关问题