在元组中搜索匹配对

时间:2018-11-28 19:18:57

标签: haskell

  

[(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上的元组上工作?

2 个答案:

答案 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