函数中的非穷尽模式[Haskell]

时间:2019-05-19 15:20:34

标签: haskell

我必须使函数成为邻居:: [(((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 == [] = []

这使得当列表不为空时,非穷尽模式消失了,但同时也阻止了函数遍历最后一个元组。

2 个答案:

答案 0 :(得分:3)

您指定的唯一模式是:

neighbours pairs@((x1,x2):xs) inputWord

因此,这意味着它仅适用于非空列表。实际上,给定模式((x1, x2):xs)会“触发”,并与列表的第一个元素(x1, x2)xs的其余元素与“ cons”匹配。

检查pair == []将永远不会成功,因为该模式已经意味着它永远不能为空列表。

我们可以为空列表模式添加一个子句,例如作为要匹配的第一个模式。此外,我们可以通过对非空列表使用(((x11, x12), x2):xs)模式来提高代码的可读性。然后,我们不需要使用fstsnd,而是可以直接使用x11x12

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)]

但是,此函数有点“不对称”,因为对于元组中的两个元素,它“优先于”第二个元素。如果两项x11x12都等于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