如何在Haskell中正确使用警卫?

Ebe*_*ley 4 haskell function list

我是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
Run Code Online (Sandbox Code Playgroud)

这个想法是,只要索引是一个Int并且elem与元素的类型相同,它就不会吓到list,但是当我尝试将它加载到ghci时,我得到"解析错误"|"".我是否需要约束参数的类型?我正在阅读Learn You A Haskell,但我还没有完全解释缩进的工作原理,所以我的错误也可能存在.

Ale*_*lec 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
Run Code Online (Sandbox Code Playgroud)

另外,请注意,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
Run Code Online (Sandbox Code Playgroud)

就个人而言,我更喜欢这个,因为它表明a并且b可以在函数的其他地方使用.

2010年Haskell报告的第4.4.3节详细介绍了where允许的位置.