我在尝试学习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)]
我如何才提取行号?我假设我会使用列表推导但我不知道该怎么做。
答案 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
也可以替换为foldMap
,join . 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]
您当然可以使用列表推导来完成所有这些工作。但您可能会发现使用map
和filter
等函数会产生更易读的代码。如果您在几个月后回顾一下代码,您将立即了解map
和filter
的目的,但需要仔细检查以确定列表理解实际上是什么做。我更喜欢仅将列表推导用于熟悉函数尚未涵盖的情况。
答案 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)
您也可以递归地定义,等等。希望它有所帮助!