使用Haskell查找列表中的第n个元素
我正在尝试编写一个函数来检索列表中的第n个元素 以下是我目前掌握的情况:使用Haskell查找列表中的第n个元素,haskell,Haskell,我正在尝试编写一个函数来检索列表中的第n个元素 以下是我目前掌握的情况: main :: IO () main = do print (nth 3 [1,2,10]) nth _ [] = [] nth a (x:xs) | (a == 1) = x | otherwise = nth (a-1) xs 这是我得到的错误: Error occurred ERROR line 2 - Cannot justify constraints in explicitly typed bin
main :: IO ()
main = do print (nth 3 [1,2,10])
nth _ [] = []
nth a (x:xs)
| (a == 1) = x
| otherwise = nth (a-1) xs
这是我得到的错误:
Error occurred
ERROR line 2 - Cannot justify constraints in explicitly typed binding
*** Expression : main
*** Type : IO ()
*** Given context : ()
*** Constraints : (Show a, Num [a])
为什么
Num[a]
约束?因为在[]
子句中,函数返回一个列表,[]
,而在另一个子句中,函数返回一个列表的元素,x
。这意味着它只为元素为列表本身的列表定义。但是你用一个[1,2,10]
列表来调用它。因此Haskell看到一个数值文本1
,并希望将其解释为一个列表,该列表也是一个数字。它还需要是Show
的一个实例,以便print
能够显示它:
Prelude> :i print
print :: (Show a) => a -> IO () -- Defined in System.IO
我们开始:
nth a (x:xs)
| (a == 1) = x
| otherwise = nth (a-1) xs
您正在返回子句中的列表
nth _ [] = []
和子句中的列表元素
nth a (x:xs)
| (a == 1) = x
| otherwise = nth (a-1) xs
所以函数的类型是
*Main> :t nth
nth :: (Eq a1, Num a1) => a1 -> [[a]] -> [a]
你可以看看这个。您的函数不能为任何列表返回任何索引的元素,因此必须使用Maybe返回“element not found”
尝试为
n
编写一个类型注释(无论如何,这是一个很好的实践)。这应该会使这里的问题更加明显。为什么不直接使用xs!!n?既然您希望nth
返回列表的元素,那么您肯定希望它的类型为Int->[a]->a
,对吗?好的,您的第一个定义,nth_[]=[]
,是一个列表(或者“返回一个列表”,如果您愿意的话),因此它是一个类型为Int->[a]->[a]
的函数的定义。那么,对于空列表,nth
该怎么办呢?这是个好问题!一种方法是简单地让它失败,另一种方法是给它返回类型可能是一个
,如果列表太短,什么也不返回。但是错误消息说什么呢?有什么想法吗?错误消息在这里没有帮助。这种情况在Haskell中经常发生,因为您没有给出足够的类型注释。由于您没有告诉它第n个n
的类型应该是什么,编译器计算出了一些惊人的(通常是相当荒谬的)签名,只注意到调用站点(这里,main
)上的一个错误,这是假的。这就是为什么您会收到一条错误消息demandigNum[a]
,这显然很奇怪,是您在其他地方犯了错误并且没有以显式类型签名的形式在那里构建安全网的典型标志之一。这就是为什么编写显式函数签名很有帮助,因此,您可以看到,您显然试图返回与您声明的类型不同的类型。@alxp完全不编写任何类型签名通常也很有帮助,尤其是对于新手,但是-加载定义后,要检查推断的签名:Prelude>let{nth_[]=[];nth a(x:xs)=x}--前奏曲>:第n--n::t->[[a]]->[a]
。
nth _ [] = Nothing
nth a (x:xs)
| (a == 1) = Just x
| otherwise = nth (a-1) xs
*Main> :t nth
nth :: (Eq a1, Num a1) => a1 -> [a] -> Maybe a