2017-08-13 49 views
0

當我嘗試使用下面的函數來實現的功能,如編譯器返回以下哈斯克爾:解析錯誤可能是不正確的縮進或不匹配的括號

解析錯誤(可能是不正確的縮進或不匹配的括號)

功能:

演示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) 

我該如何糾正? 關心!

+1

'可能不正確的縮進'。 'let..in'塊看起來不正確的縮進。嘗試嘗試縮進以獲取代碼進行編譯。 –

+0

'let arg = arg-1'和'let n = n + 1'是遞歸定義,定義'arg'和'n'爲無限循環計算。你不想那樣。你正在試圖改變Haskell中的變量,這是爲了讓這個變得不可能。這種方法對於在FP語言中工作來說太過緊迫。粗略地說,「改變」一個變量的唯一方法是用新值調用一個函數,例如。 'f 0 = 0; f n = f(n-1)'定義了一個遞歸,「遞減」n直到它達到0. – chi

回答

2

你不能在頂層寫let n = 0。刪除該代碼後,代碼的else let部分也不會正確縮進,因爲其用途(do塊外部)始終爲let ... in ...,並且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 

請注意,沒有必要使用length,這是件好事! length在無限列表上發散,而這會優雅地處理它們。

1

你混合當務之急和功能範例:let n = 0let (x:xs) = (x:xs) ++ (x:xs)!!narg = arg - 1n = n + 1是(在你的代碼)勢在必行表達式。您期望修改n,(x:xs)arg的值,但函數式編程不能像那樣工作。

你聲明的功能是爲了:這意味着你不能期望值被修改(我們稱之爲「副作用」)。你唯一能做的就是用新的參數調用一個新的函數(或者相同的函數),這些新的參數是從原始參數「實時」計算出來的。

讓我們試着具體。

你不能做:

arg = arg - 1 
demo arg (x:xs) 

但你可以這麼做:

demo (arg - 1) (x:xs) 

後者是demoarg - 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]) ``` 

現在,從你給的例子,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),但我想貼近你原來的執行。

+0

謝謝jferard!你的代碼正是我的意思。我認爲問題是由變量n引起的,但我不知道如何解決這個問題,謝謝回答我的問題。 – Sean

+0

@Sean歡迎您。你應該接受我的答案或者ephemient的答案。 – jferard