haskell - 自己的版本inits - list comprehensions

时间:2016-03-07 22:42:09

标签: haskell

查看以下版本的inits:

inits4 :: [a] -> [[a]]
inits4 [] = [[]]
inits4 (x:xs) = []:[x:ys | ys <- inits4 xs]

我知道如何工作理解列表,但这种情况太可怕了。请问有人试图解释一下吗?

2 个答案:

答案 0 :(得分:1)

你说

inits4 :: [a] -> [[a]]
inits4 [] = [[]]
inits4 (x:xs) = []:[x:ys | ys <- inits4 xs]

我希望你能自己找出第一个案例。第二种可以机械翻译为do符号:

inits4 (x : xs) = [] : do
  ys <- inits4 xs
  return (x : ys)

我们可以去除

inits4 (x : xs) =
  [] : (inits4 xs >>= \ys -> return (x : ys))

我们有一项法律

m >>= \a -> return (f a) = fmap f m

所以

inits4 (x : xs) =
  [] : fmap (x :) (inits4 xs)

由于inits4会生成一个列表,fmap = map,您应该能够完成其余的工作。

请注意,此实现存在严重的效率问题,不应在实际代码中使用。无条件渐近最优性能的最简单实现可能是

inits xs = [] : zipWith (\i _ -> take i xs) [1..] xs

答案 1 :(得分:0)

要理解递归的情况,假设我们想要计算

inits4 [x1,...,xn] =
[ [], [x1], [x1, x2], [x1, x2, x3], ..., [x1, ..., xn] ]

我们首先在列表的尾部计算inits4。通过归纳,我们得到了

inits4 [x2,...,xn] =
[ [], [x2], [x2, x3], ..., [x2, ..., xn] ]

如何将上述内容转换为想要的结果。好吧,我们需要将x1添加到列表列表中的每个列表中。我们可以用列表理解

来做到这一点
[x1:y | y <- inits4 [x2,...,xn]] =
[ x1:[], x1:[x2], x1:[x2, x3], ..., x1:[x2, ..., xn] ] =
[ [x1], [x1, x2], [x1, x2, x3], ..., [x1, x2, ..., xn] ] =

这几乎是我们想要的!我们只添加添加空列表:

[] : [x1:y | y <- inits4 [x2,...,xn]] =
[ [], [x1], [x1, x2], [x1, x2, x3], ..., [x1, x2, ..., xn] ]