我是哈斯凯尔的新手。试图用递归实现一些非常简单的东西。返回列表中第一个匹配值的索引的函数。下面的代码不起作用,不知道为什么,有谁知道如何更正此代码?
linear_search :: (Eq a) => a -> [a] -> a
linear_search b w = linear_search_tail 0 b w
where linear_search_tail :: (Eq a) => a -> a -> [a] -> a
linear_search_tail x y [] = -1
linear_search_tail x y (z:zs)
| y == z = x
| otherwise = linear_search_tail (x+1) y zs
main :: IO ()
main = print (linear_search 1 [2,5,4,3,7,3,1,2,3,4,5,7,8])
编辑:搞定了。这是正确的代码:
#!/usr/bin/env runghc
linear_search :: (Eq a) => a -> [a] -> Int
linear_search b w = linear_search_tail 0 b w
where linear_search_tail :: (Eq a) => Int -> a -> [a] -> Int
linear_search_tail x y [] = -1
linear_search_tail x y (z:zs)
| y == z = x
| otherwise = linear_search_tail (x+1) y zs
main :: IO ()
main = print (linear_search 1 [2,5,4,3,7,3,1,2,3,4,5,7,8])
答案 0 :(得分:3)
代码正在搜索数字的索引,这意味着应返回Int
:
linear_search :: (Eq a) => a -> [a] -> Int
还有一个类似的问题,看看你能不能找到答案!
linear_search_tail :: (Eq a) => Int -> a -> [a] -> Int
答案 1 :(得分:3)
让我对纠正后的代码添加一些评论:
linear_search :: (Eq a) => a -> [a] -> Int
linear_search b w = linear_search_tail 0 b w
where linear_search_tail :: (Eq a) => Int -> a -> [a] -> Int
linear_search_tail x y [] = -1
linear_search_tail x y (z:zs)
| y == z = x
| otherwise = linear_search_tail (x+1) y zs
在辅助函数中,第二个参数y
不变地传递,所以它总是等于b
。您可以删除参数并直接使用:
linear_search :: (Eq a) => a -> [a] -> Int
linear_search b w = linear_search_tail 0 w
where -- linear_search_tail :: (Eq a) => Int -> [a] -> Int
linear_search_tail x [] = -1
linear_search_tail x (z:zs)
| b == z = x
| otherwise = linear_search_tail (x+1) zs
(这里我必须删除/注释内部类型签名,因为Haskell将内部a
类型变量解释为独立于外部a
- 您可以通过启用来声明它们是相同的扩展,但让我们保持简单,只是省略签名。)
上述函数在出错时返回-1
。这在Haskell中不是惯用的,其中更常见的是返回Maybe Int
,这是一个包含表示整数Just 0, Just 1, Just 2, ...
的值加上可以解释为“no”的不同值Nothing
的类型结果”。如果我们使用它,我们得到:
linear_search :: (Eq a) => a -> [a] -> Maybe Int
linear_search b w = linear_search_tail 0 w
where linear_search_tail x [] = Nothing
linear_search_tail x (z:zs)
| b == z = Just x
| otherwise = linear_search_tail (x+1) zs
请注意,这会使生命更少更方便调用者,现在将其索引包装在Just
框中,或Nothing
。这实际上是一件好事,因为现在调用者不能轻易忘记检查“未找到”的情况并使用一个普通的整数来假装它不是-1
。调用者现在被迫使用类似
case linear_search 1 [2,3,4,5] of
Just x -> "Found at position " ++ x
Nothing -> "Not found!"
最后,请注意第一行
linear_search b w = linear_search_tail 0 w
也可以写成
linear_search b = linear_search_tail 0
也就是说,您可以在定义的尾随位置省略相同的变量。这称为eta-reduction,并不一定会使您的代码看起来更好。在这种情况下,它没有多大帮助。我只是提到它,因为你可能会在将来看到这样的代码。
在您学习了更多Haskell之后,您可能想知道如何利用库函数。例如,来自elemIndex
的{{1}}库函数执行您尝试编写的线性搜索。可替代地,
Data.List
你可能现在发现这个不可读,但是你可以继续学习,并在你更熟悉Haskell之后再回过头来。与此同时,像你一样编写递归函数是正确的方法。