为什么期望 (String, Int) 而不是 (Char, Int)?

Why (String, Int) is expected instead of (Char, Int)?

我完全不知道为什么以下方法不起作用:

takeRange :: Int -> (a,Int) -> [(a,Int)] -> [(a,Int)]
takeRange n elem list = dropWhile (\x -> snd x < snd elem) (takeWhile (\x -> snd x < (snd elem) + n) list)

seriesLargestProd :: String -> Int -> Int
seriesLargestProd "" _ = 0
seriesLargestProd _ 0 = 0
seriesLargestProd s n = maximum [foldl1 (*) $ map (read . fst) (takeRange n pair zipped)
                                | pair <- zipped, snd pair <= lastStartingIndex] 
                                    where zipped = zip s [1..]
                                          lastStartingIndex = (length s) - (n-1)

我收到的错误消息:

Couldn't match type `Char' with `[Char]'
    Expected type: (String, Int)
      Actual type: (Char, Int)
    In the second argument of `takeRange', namely `pair'
    In the second argument of `map', namely `(takeRange n pair zipped)'

Couldn't match type `Char' with `[Char]'
    Expected type: [(String, Int)]
      Actual type: [(Char, Int)]
    In the third argument of `takeRange', namely `zipped'
    In the second argument of `map', namely `(takeRange n pair zipped)'

如果有人感兴趣,这应该是 Project Euler 问题 8 的答案。

Why a String is expected, when zip will clearly "disunite" the string into individual characters?

因为 read 需要一个字符串。为了将单个数字转换为整数,请使用 digitToInt,而不是 read(或者您也可以使用 read [theChar] 来创建一个单字符字符串并将其转换,但没有必要因为这里 digitToInt 存在)。

PS:代替snd xsnd pair,使用模式匹配来单独命名对的元素会更加惯用。

您正在映射的函数 read . fst 具有类型 Read a => (String, b) -> a。所以map (read . fst) :: Read a => [(String, b)] -> [a]。但是 zipped 具有 [(Char, Int)] 类型,并且 takeRange returns 与输入的列表类型相同。

顺便说一句,您可以将 takeRange 实现为

takeRange n elem list = take n $ drop (snd elem) $ list

您正在通过手动计算索引来做额外的工作,正如@sepp2k 提到的那样,这对于元组上的模式匹配会更加惯用。