[(3,9),(4,16),(5,25)] 4 = 16
我当时使用map (\(x,y ) -> x) [(3,9),(4,16),(5,25)]
来获取每个元素的fst,然后将其过滤以进行匹配-但是我在使第一部分起作用时遇到了错误:
findTup :: Rel -> Int -> Int
findTup rs a = map (\(x,y ) -> x) rs
- 无法将预期的类型“ Int”与实际类型“ [Int]”匹配
- 在表达式中:map(\(x,y)-> x)rs
有什么方法可以使地图在Int -> Int
上的元组上工作?
答案 0 :(得分:0)
让我们从findTup
的价格开始。如果我们将您的函数放入ghci中,并要求其提供类型,我们就会得到
ghci> findTup rs a = map (\(x,y) -> x) rs
ghci> :t findTup
findTup :: [(b1, b2)] -> p -> [b1]
这告诉我们,您的函数返回的列表具有某种类型b1
,鉴于map的类型签名为map :: (a -> b) -> [a] -> [b]
,这是有意义的。将给定函数应用于列表中每个元素的另一个函数对filter
更为有用。过滤器的类型签名为filter :: (a -> Bool) -> [a] -> [a]
。
因此,让我们尝试用map
替换代码中的filter
,得到findTup rs a = filter (\(x, y) -> x) rs
。现在,如果检查类型,我们发现它是findTup :: [(Bool, b)] -> p -> [(Bool, b)]
。此功能仍然存在一些问题。对于初学者来说,(\(x, y) -> x)
限制我们的输入在元组的第一项中包含布尔值,但这不是我们想要的。我们需要重写过滤功能,以便它实际执行搜索。 (\(x, y) -> x == a)
是我们真正想要的。这将导致过滤器仅返回与我们要搜索的元素匹配的元素。现在我们可以看到findTup :: Eq a => [(a, b)] -> a -> [(a, b)]
。
不幸的是,它仍然返回一个列表,我们只需要一个项目。我们可以使用head
函数仅获取匹配的第一项,因此findTup rs a = head $ filter (\(x, y) -> x == a) rs
。 Ghci告诉我们此函数的签名为findTup :: Eq a => [(a, b)] -> a -> (a, b)
,与我们想要的非常接近。剩下的唯一事情就是从元组中获取第二个值,我们可以使用函数snd
来完成此操作。
因此,我们的最终代码将为findTup rs a = snd . head $ filter (\(x, y) -> x == a) rs
。快速检查ghci显示findTup :: Eq a => [(a, b)] -> a -> b
。用Int
代替类型变量,我们发现findTup :: [(Int, Int)] -> Int -> Int
答案 1 :(得分:0)
问题是您声明的类型与您的部分实现不匹配。您可以简单地更改类型,直到进行过滤为止:
findTup :: Rel -> Int -> [Int]
findTup rs a = map (\(x,y) -> x) rs
或添加过滤条件。为此,显式递归和模式匹配比使用map
更简单:
findTup :: Rel -> Int -> Int
-- findTup [] a = ... -- Omitted to reflect the assumption of success
findTup ((k, v):rs) a = if k == a then v else findTup rs a
但是,无需重新发明轮子:
import Data.Maybe
findTup :: Rel -> Int -> Int
findTup rs a = fromJust (lookup a rs)
或者,因为您可能不应该假定查找将成功,所以
findTup :: Rel -> Int -> Maybe Int
findTup = flip lookup