2017-03-06 33 views
3

我是Haskell的新手,我正在嘗試編寫簡單的函數來使自己適應語法,我想編寫自己的函數來將特定元素添加到特定索引的列表中。下面是我在Atom中寫道(我的文本編輯器):如何正確使用哈斯克爾的守衛?

addElem :: a->[a]->Int->[a] 
addElem elem list index 
| index <= 0   = elem:list 
| index < (length list) = a ++ (elem:b) where a = take index list; b = drop index list 
| otherwise    = list 

的想法是,它不會驚慌,只要指數是Intelem是同一類型的list元素,但是當我嘗試將這個加載到ghci時,我得到了「|'解析錯誤。」我是否需要約束參數的類型?我正在閱讀學習你一個Haskell,但我沒有得到他們完全解釋縮進如何工作的部分,所以我的錯誤也可能在那裏。

+3

「where」塊未附加到表達式,即「x其中decls」不是表達式(與「let decls in x」,這是一個表達式)不同。一個'where'塊必須附加到一個聲明中,在這種情況下,你可能希望它附加到'addElem'聲明中,所以必須放在*聲明體之後,最後一個聲明體也是它的一部分。請注意,解析錯誤與使用錯誤的類型無關 - 它意味着編譯器甚至不理解你的代碼,更不用說判斷它是錯誤的了。這也不是縮進錯誤。 – user2407038

+2

@ user2407038應該是一個答案 – jberryman

+0

如果'index'太大,你是否真的想要忽略'elem'?與'index'<0時的元素相比,這有點不對稱。我會認爲'否則= list ++ [elem]'會有意義。 – chepner

回答

11

where塊需要發生在整個函數的末尾,並在所有情況下共享。你可能意味着使用let

addElem :: a -> [a] -> Int -> [a] 
addElem elem list index 
| index <= 0   = elem:list 
| index < (length list) = let a = take index list; b = drop index list in a ++ (elem:b) 
| otherwise    = list 

另外,還要注意let可以更簡明地寫爲let (a,b) = splitAt index list in ...splitAt也在前奏。當然,你也可以將where塊移到該函數的末尾(Haskell的懶惰使得這很容易推理)。

addElem :: a -> [a] -> Int -> [a] 
addElem elem list index 
| index <= 0   = elem:list 
| index < (length list) = a ++ (elem:b) 
| otherwise    = list 
where 
    a = take index list 
    b = drop index list 

就個人而言,我喜歡這樣的少,因爲它表明ab可在功能別處使用。

2010 Haskell Report的第4.4.3節更詳細地討論了允許的where的位置。