【问题标题】:Non-exhaustive patterns in a function [Haskell]函数中的非详尽模式 [Haskell]
【发布时间】:2019-05-19 15:20:34
【问题描述】:

我必须创建一个函数邻居 :: [((String, String), Int)] -> String -> [(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 == [] = []

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

【问题讨论】:

  • 既然你用pairs@((x1,x2):xs)作为模式,pairs == []永远不会是真的。
  • 我不太明白你的意思
  • 你明白(_:_)模式的含义吗?

标签: haskell


【解决方案1】:

您指定的唯一模式是:

neighbours <b>pairs@((x1,x2):xs)</b> inputWord

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

检查pair == [] 永远不会成功,因为模式已经意味着这永远不会是一个空列表。

我们可以为空列表模式添加一个子句,例如作为第一个匹配的模式。此外,我们可以通过对非空列表使用((<b>(x11, x12)</b>, 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,则yield 这两个项目可能更有意义。

【讨论】:

    【解决方案2】:

    如果您定义一个辅助函数来与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
    

    考虑到这种模式,我们可以通过使用来自Data.MaybemapMaybe 而不是concatMap,来切换到对myLookup 使用更严格的Maybe Bar 返回类型。

    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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多