我必须使函数成为邻居:: [(((String,String),Int)]->字符串-> [(String,Int)]
这是我想出的功能:
neighbours pairs@((x1,x2):xs) inputWord
| pairs == [] = []
| fst x1 == inputWord = ((snd x1), x2) : (neighbours xs inputWord)
| snd x1 == inputWord = ((fst x1), x2) : (neighbours xs inputWord)
| otherwise = (neighbours xs inputWord)
输出应该是一个元组列表,其中包含与元组x1中的inputWord配对的字符串以及整数x2
问题是我得到了我认为不应该存在的非穷尽模式。
我尝试将pairs == [] = []
替换为xs == [] = []
这使得当列表不为空时,非穷尽模式消失了,但同时也阻止了函数遍历最后一个元组。
答案 0 :(得分:3)
您指定的唯一模式是:
neighbours pairs@((x1,x2):xs) inputWord
因此,这意味着它仅适用于非空列表。实际上,给定模式((x1, x2):xs)
会“触发”,并与列表的第一个元素(x1, x2)
与xs
的其余元素与“ cons”匹配。
检查pair == []
将永远不会成功,因为该模式已经意味着它永远不能为空列表。
我们可以为空列表模式添加一个子句,例如作为要匹配的第一个模式。此外,我们可以通过对非空列表使用(((x11, x12), x2):xs)
模式来提高代码的可读性。然后,我们不需要使用fst
和snd
,而是可以直接使用x11
和x12
:
neighbours :: Eq a => [((a, a), b)] -> a -> [(a, b)]
neighbours [] _ = []
neighbours pairs@(((x11, x12),x2):xs) inputWord
| inputWord == x11 = (x11, x2) : tl
| inputWord == x12 = (x12, x2) : tl
| otherwise = tl
where tl = neighbours xs inputWord
例如:
Prelude> neighbours [(('a', 'b'), 1), (('b', 'a'), 2), (('b', 'b'), 3), (('a', 'a'), 4)] 'a'
[('a',1),('a',2),('a',4)]
但是,此函数有点“不对称”,因为对于元组中的两个元素,它“优先于”第二个元素。如果两项x11
和x12
都等于inputWord
,则屈服这两个变量可能更有意义。
答案 1 :(得分:1)
如果您定义一个辅助函数来与inputWord
进行比较,则neighbors
的定义会变得更加简单:
-- You can use other, more descriptive names instead.
type Foo = ((String, String), Int)
type Bar = (String, Int)
-- If it seems odd that I'm using [Bar] instead of Maybe Bar, see below
myLookup :: String -> Foo -> [Bar]
myLookup s ((s1, s2), i) | s == s1 = [(s2, i)]
| s == s2 = [(s1, i)]
| otherwise = []
neighbors :: [Foo] -> String -> [Bar]
neighbors [] _ = []
neighbors (x:xs) inputWord = case myLookup inputWord x of
[] -> neighbors xs inputWord
[y] -> y : neighbors xs inputWord
使用concatMap
(可以简单地将其串联起来)进一步简化
将myLookup inputWord
应用于输入的每个元素的结果。
neighbors :: [Foo] -> String -> [Bar]
neighbors xs inputWord = concatMap (myLookup inputWord) xs
牢记这一模式,我们可以通过使用Maybe Bar
中的myLookup
而不是mapMaybe
来为Data.Maybe
使用更严格的concatMap
返回类型。
import Data.Maybe (mapMaybe)
type Foo = ((String, String), Int)
type Bar = (String, Int)
myLookup :: String -> Foo -> Maybe Bar
myLookup s ((s1, s2), i) | s == s1 = Just (s2, i)
| s == s2 = Just (s1, i)
| otherwise = Nothing
neighbors :: [Foo] -> String -> [Bar]
neighbors xs inputWord = mapMaybe (myLookup inputWord) xs