递归查找包含子字符串的字符串的索引

时间:2019-04-22 15:14:44

标签: haskell recursion

我试图在包含某个子字符串但无济于事的列表的上下文中查找字符串的索引。不确定如何将整个未修改数组作为递归函数中另一个函数的参数传递。这是我的方法:

find' :: [String] -> Maybe Int
find' [] = error "List is empty"
find' [x] = return maybe 0
find' (x:xs)
    | "HU" `isInfixOf` x = return elemIndex x (x:xs)
    | otherwise = checkTail
    where checkTail = find' xs

错误是:

 * Couldn't match type `[[String]] -> Maybe Int' with `Maybe Int'
  Expected type: String -> [String] -> Maybe Int
    Actual type: String -> [String] -> [[String]] -> Maybe Int
* The function `return' is applied to three arguments,
  but its type `([String] -> [[String]] -> Maybe Int)
                -> String -> [String] -> [[String]] -> Maybe Int'
  has only four
  In the expression: return elemIndex x (x : xs)
  In an equation for find':
      find' (x : xs)
        | "HU" `isInfixOf` x = return elemIndex x (x : xs)
        | otherwise = checkTail
        where
            checkTail = find' xs

   | "HU" `isInfixOf` x = return elemIndex x (x:xs)
                      ^^^^^^^^^^^^^^^^^^^^^^^^^

我不太理解错误以及为什么不匹配,因为在两种情况下,im都返回一个int值。但是,正如我前面提到的,我不确定(x:xs)是否实际上意味着该参数的整个列表。 为了澄清,我试图从字符串列表中找到字符串的索引。

1 个答案:

答案 0 :(得分:2)

首先,maybe本身就是一个函数;它与问题无关。可以说return 0可以满足您的要求:它会从函数中返回Just 0

find' :: [String] -> Maybe Int
find' [] = Nothing
find' [x] = return 0 -- equivalent to find' [x] = Just 0

(请注意使用Nothing;如果要引发错误,则没有理由使用Maybe Int而不是Int作为返回类型。而且,也没有理由在return上使用Just,因为您不是要在此处支持任意monad。)

此外,elemIndex 已经返回类型为Maybe Int的值;您不需要使用return函数,该函数将值包装在另一层中,生成Maybe (Maybe Int)值,这不是您想要的。

find' (x:xs)
    | "HU" `isInfixOf` x = elemIndex x (x:xs)
    | otherwise = find' xs

最后一个问题:如果列表的第一个元素中没有"HU",那么只需在列表的尾部调用find'是正确的。但是,您需要在该返回值上加1以补偿传递较短的参数。 (这也意味着您不需要elemIndex,因为您总是在 current 列表的开头找到"HU"。)

find' (x:xs)
    | "HU" `inInfixOf` x = Just 0
    | otherwise = fmap (1+) (find' xs)

您需要使用fmap; find'返回Maybe Int,而不是Int,因此1 + find' xs本身将不起作用。

这也意味着您可以删除[x]的特殊情况,因为它是从列表开头查找搜索字符串得出的。整个功能就是

find' :: [String] -> Maybe Int
find' [] = Nothing
find' (x:xs)
    | "HU" `isInfixOf` x = Just 0
    | otherwise = fmap (1+) (find' xs)

使用整个列表的一种方法是一次搜索整个列表,然后在生成的布尔值列表中找到(第一个)True。

find'' :: [String] -> Maybe Int
find'' xs = elemIndex True (map ("HU" `inInfixOf`) xs)
-- or find'' = elemIndex True . map ("HU" `inInfixOf`)
-- or find'' = findIndex ("HU" `inInfixOf`)