Haskell列表理解

时间:2013-08-08 15:03:17

标签: list haskell list-comprehension

我在尝试学习Haskell时试图做一个haskell问题。

这个问题给出了以下类型定义:
type Word = String
type Line = [Word]
type Book = [Line]

然后问题我要求定义一个函数索引:: Word - >书 - > [Int]采用单词和书籍,并返回单词出现的行号。例如:
index "example" [["example", "town"], ["example", "cat", "this"]] = [1,2]

到目前为止,我已经使用了zip book [1 ..长度书]将行号附加到每一行,这样就可以给我了

[(["example","town"],1),(["example","cat","this"],2)]

我如何才提取行号?我假设我会使用列表推导但我不知道该怎么做。

3 个答案:

答案 0 :(得分:5)

这些事情的一般列表理解方案是

g xs = [i | (x,i) <- zip xs [1..], pred x]

pred是一个谓词,作用于输入列表xs的元素;仅对于那些通过测试的人,他们的原始索引包含在输出中。当然,这可以通过更高阶函数来完成,如

g xs = map snd . filter (pred . fst) . (`zip` [1..]) $ xs

(.)是函数组合运算符:pred . fst == (\p -> pred (fst p))。因此,上述行也可以写成

g xs = map snd . filter (\(x,i) -> pred x) . (`zip` [1..]) $ xs

对你来说更具可读性。

更新: filter也可以实现为

filter pred = concatMap (\x -> [x | pred x])

所以映射可以融合在一起,给我们

g :: (a -> Bool) -> [a] -> [Int]
g pred = concatMap (\(x,i) -> [i | pred x]) . (`zip` [1..])

concatMap也可以替换为foldMapjoin . map ...甚至asum . map ...

答案 1 :(得分:2)

您可以使用map,它将函数应用于列表中的每个元素。您要应用的函数是snd,它会提取第二个元素。

λ> let xs = [(["example","town"],1),(["example","cat","this"],2)]
λ> map snd xs
[1,2]

您可能希望向我们展示其余的代码。您提到您使用了Tzip book [1 .. length book] - 通常比使用length函数更简单,更有效。我们或许可以建议采用更“Haskellish”的方式。

修改:过滤

我们可以通过编写一个简单的函数来过滤列表,以查找包含我们感兴趣的单词的所有条目。在下面的示例中,我为此目的定义了containsWord

λ> let xs = [(["example","town"],1),(["example","cat","this"],2)]
λ> let containsWord w (ws,_) = w `elem` ws
λ> let ys = filter (containsWord "cat") xs
λ> map snd ys
[2]

或者,如果你想定义内联函数:

λ> let xs = [(["example","town"],1),(["example","cat","this"],2)]
λ> let ys = filter (\(zs,_) -> "cat" `elem` zs) xs
λ> map snd ys
[2]

您当然可以使用列表推导来完成所有这些工作。但您可能会发现使用mapfilter等函数会产生更易读的代码。如果您在几个月后回顾一下代码,您将立即了解mapfilter的目的,但需要仔细检查以确定列表理解实际上是什么。我更喜欢仅将列表推导用于熟悉函数尚未涵盖的情况。

答案 2 :(得分:2)

正如其他帖子所述,您可以使用zip函数使用行号来装饰每一行。然后,您可以使用列表推导来搜索:

search :: Word -> Book -> [Int]  
search w b =  
  [n | (line, n) <- lines, elem w line]  
  where lines = zip b [1..]

您也可以使用foldl定义该函数(不确定它的风格是否很好,我仍然是Haskell的初学者):

search :: Word -> Book -> [Int]
search w b =
  fst $ foldl foo ([], 1) b
  where foo (rs, n) line | elem w line = (n : rs, n+1)
                         | otherwise = (rs, n+1)

您也可以递归地定义,等等。希望它有所帮助!