List 在列表中查找对

List 在列表中查找对,list,haskell,List,Haskell,我试图在列表中查找元素对,假设它们是列表中唯一的一对,并且不超过3个相同的连续元素 我有一个函数,它接受一个列表,并返回该对中第一个元素的索引(如果有)。如果不是,则返回-1 searchForPairs xs = searchHelp xs ((genericLength xs) - 1) where searchHelp xs n | searchHelp xs 0 = -1 -- no pairs found | (xs !

我试图在列表中查找元素对,假设它们是列表中唯一的一对,并且不超过3个相同的连续元素

我有一个函数,它接受一个列表,并返回该对中第一个元素的索引(如果有)。如果不是,则返回-1

searchForPairs xs = searchHelp xs ((genericLength xs) - 1)
    where searchHelp xs n
        | searchHelp xs 0 = -1              -- no pairs found
        | (xs !! n) == (xs !! (n - 1)) = n
        | otherwise = searchHelp xs n-1
出于某种原因,它返回错误:

Couldn't match expected type `Bool' with actual type `Int'
In the expression: n
In an equation for `searchHelp':
    searchHelp xs n
      | searchHelp xs 0 = - 1
      | (xs !! n) == (xs !! (n - 1)) = n
      | otherwise = searchHelp xs n - 1
In an equation for `searchForPairs':
    searchForPairs xs
      = searchHelp xs ((genericLength xs) - 1)
      where
          searchHelp xs n
            | searchHelp xs 0 = - 1
            | (xs !! n) == (xs !! (n - 1)) = n
            | otherwise = searchHelp xs n - 1

看来应该行得通。你知道为什么不是吗

您有两个问题。第一个是在这一行:

        | otherwise = searchHelp xs n-1
编译器将其解释为
(searchHelp xs n)-1
,而不是您想要的
searchHelp xs(n-1)
。第二个问题是在使用防护装置时:

        | searchHelp xs 0 = -1              -- no pairs found
由于
searchHelp xs 0
不是布尔表达式(您希望将其用作模式),编译器拒绝了它。我可以看到两个简单的解决方案:

searchForPairs xs = searchHelp xs ((genericLength xs) - 1)
    where searchHelp xs n
        | n == 0 = -1              -- no pairs found
        | (xs !! n) == (xs !! (n - 1)) = n
        | otherwise = searchHelp xs (n-1)

现在,不幸的是,尽管这是可行的,但效率非常低。这是因为您使用了
。在Haskell中,列表是链表,因此
xs!!n
将采取n个步骤,而不是1个步骤。这意味着函数所花费的时间是列表长度的二次方。要纠正此问题,请使用模式匹配沿列表向前循环:

searchForPairs xs = searchHelp xs 0 where
    searchHelp (x1 : x2 : xs) pos
        | x1 == x2 = pos
        | otherwise = searchHelp (x2 : xs) (pos + 1)
    searchHelp _ _ = -1

@gereeter已经解释了您的错误,我只想指出,如果找不到答案,您不应该返回
-1
。相反,如果没有答案,则应返回
Nothing
;如果答案是
pos
,则应返回
Just pos
。这可以保护您免受多种错误的影响。

我不知道您想做什么,但从代码来看,您似乎试图在列表中找到两个相等的连续元素。而不是使用
要为列表编制索引,可以使用模式匹配提取列表的前两个元素,检查它们是否相等,如果不相等,则继续搜索其余元素(包括第二个元素)。如果列表中没有至少两个元素,则返回
Nothing

searchForPairs xs = go 0 xs where
  go i (x1:xs@(x2:_)) | x1 == x2 = Just i
                      | otherwise = go (i+1) xs
  go _ _ = Nothing

值得一提的是,下面是一个有点惯用(无点)的实现,它实现了您正在尝试做的事情:

searchPairs :: Eq a => [a] -> Maybe Int
searchPairs = interpret . span (uncurry (/=)) . (zip <*> tail)
    where
    interpret (flag, res) = if null flag then Nothing else Just $ length res
searchPairs::Eq a=>[a]->Maybe Int
searchPairs=解释。span(未修剪(/=))。(拉链尾)
哪里
exploration(flag,res)=如果为null标志,则除此之外没有其他内容,只有$length res

说明:
zip-tail
创建连续元素对的列表(使用reader应用程序类型类)
uncurry(/=)
测试这样一对是否由相同的元素组成。最后,
explorate
将结果转换为
可能是Int
type的值。

根本问题是什么?您试图实现什么?避免返回哨兵值,如
-1
,以指示失败。用
也许
代替。@AndrewC不是
只有5个
而不是
也许5个
?啊!更正:您似乎想用零替换大量数据。为什么会这样?哈马尔说得对,如果在第5位有一对,你应该只使用
5
,如果没有对,你应该使用
什么都没有
searchPairs :: Eq a => [a] -> Maybe Int
searchPairs = interpret . span (uncurry (/=)) . (zip <*> tail)
    where
    interpret (flag, res) = if null flag then Nothing else Just $ length res