2017-03-06 35 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的位置。