gpt4 book ai didi

list - Haskell 中的最长公共(public)前缀

转载 作者:行者123 更新时间:2023-12-05 08:58:38 25 4
gpt4 key购买 nike

我正在尝试根据文件的最长公共(public)前缀 cpfx 来匹配文件,我对 haskell 有点陌生。我正在尝试获取列表列表并简单地返回它们共享的前缀。例如:

cpfx ["obscure","obscures","obscured","obscuring"] --> "obscur"

cpfx ["abc", "ab", "abcd"] --> "ab"

我正在尝试使用一些辅助方法来实现这一点,如下所示:

cpfx :: [[Char]] -> [Char]
cpfx [] = [] -- nothing, duh
cpfx (x:[]) = x -- only one thing to test, return it
cpfx (x:t) = cpfx' (x:t) 0 -- otherwise, need to test

cpfx' (x:[]) _ = []
cpfx' (x:t) n
-- call ifMatch to see if every list matches at that location, then check the next one
| ifMatch (x:t) n = x!!n + cpfx' x (n+1)
| otherwise = []

-- ifMatch means if all words match at that location in the list
ifMatch (x:[]) _ = True
ifMatch (x:xs:[]) n = x!!n == xs!!n
ifMatch (x:xs:t) n
| x!!n == x!!n = ifMatch xs n
| otherwise = False

但是我得到了错误:发生检查:无法构造无限类型:a0 = [a0]

我猜这与 ifMatch (x:t) n = x!!n + cpfx' x (n+1) 行有关。

我能做些什么来补救这种情况?

最佳答案

如何解决这些错误

注意:虽然我将向您展示如何理解和解决这些错误,但我还在下面提供了一个更优雅的版本(至少从我的角度来看)。

每当你以无限类型结束时,最好也添加类型签名:

cpfx'   :: [[Char]] -> Int -> [Char]
ifMatch :: [[Char]] -> Int -> Bool

突然间,我们得到了额外的错误,两个错误

  | ifMatch (x:t) n = x!!n + cpfx' x (n+1)
 Couldn't match expected type `[Char]' with actual type `Char'    Expected type: [[Char]]      Actual type: [Char]    In the first argument of `(!!)', namely `x'    In the first argument of `(+)', namely `x !! n'
    No instance for (Num [Char])      arising from a use of `+'

and one in ifMatch:

  | x!!n == x!!n = ifMatch xs n
    Couldn't match expected type `[Char]' with actual type `Char'    Expected type: [[Char]]      Actual type: [Char]    In the first argument of `ifMatch', namely `xs'    In the expression: ifMatch xs n

Now, the error in cpfx' is quite simple: x is a [Char], x !! n is a Char, and want to cons it onto a list, so use : instead of +. Also, you want to apply cpfx' to t, not to x. This also fixes your second error. In ifMatch, x!!n == x!!n is redundant, and xs has type [Char] and thus hasn't the right type for ifMatch. This is also a typo:

  | x!!n == xs!!n = ifMatch t n

但是,既然我们修复了这些编译错误,您的程序是否真的有意义?特别是,您希望这几行做什么:

ifMatch (x:xs) n = x!!n : cpfx' xs (n+1)

(x:xs) 是您的单词列表。但是,您在每次迭代中都从中删除了一个词,这显然不是您的意思。你要

ifMatch (x:xs) n = x!!n : cpfx' (x:xs) (n+1)

总的来说,我们得到以下代码:

cpfx :: [[Char]] -> [Char]
cpfx [] = []
cpfx [x] = x
cpfx (x:xs) = cpfx' (x:xs) 0

cpfx' :: [[Char]] -> Int -> [Char]
cpfx' [x] _ = []
cpfx' (x:xs) n
| ifMatch (x:xs) n = x!!n : cpfx' (x:xs) (n+1)
| otherwise = []

ifMatch :: [[Char]] -> Int -> Bool
ifMatch [x] _ = True
ifMatch [x,y] n = x!!n == y!!n
ifMatch (x:y:xs) n
| x!!n == y!!n = ifMatch xs n
| otherwise = False

使用折叠的更简单方法

让我们的函数更简单一点,但也更通用,方法是为实现 == 的任何类型编写一个 commonPrefix:

commonPrefix :: (Eq e) => [e] -> [e] -> [e]
commonPrefix _ [] = []
commonPrefix [] _ = []
commonPrefix (x:xs) (y:ys)
| x == y = x : commonPrefix xs ys
| otherwise = []

如果您不习惯这种表示法,暂时将e 想象成Char。现在,一些词的公共(public)前缀可以写成:

"hello" `commonPrefix` "hell" `commonPrefix` "hero"

现在的问题是,如果你想为一系列事情做某事,你通常使用 fold :

foldl :: (a -> b -> a) -> a -> [b] -> a

foldl, applied to a binary operator, a starting value (typically the left-identity of the operator), and a list, reduces the list using the binary operator, from left to right:

foldl f z [x1, x2, ..., xn] == (...((z `f` x1) `f` x2) `f`...) `f` xn

最后一个例子看起来和我们之前的 `commonPrefix` 行一模一样!但是,我们没有起始值,因此我们将使用列表的第一个元素。幸运的是,已经有 foldl1 ,正是这样做的。因此,我们之前复杂的函数归结为:

commonPrefixAll :: (Eq a) => [[a]] -> [a]
commonPrefixAll = foldl1 commonPrefix

您应该记住的一点是:每当您想遍历列表中的多个元素以提供单个值时,请考虑是否真的有必要在每次迭代中查看所有元素。通常,一次只关注两个元素然后使用正确的折叠就足够了。请参阅 Computing one answer over a collection in Real World Haskell 部分获取更多示例和信息。

关于list - Haskell 中的最长公共(public)前缀,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21717646/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com