使用列表理解实现 take 函数

Implement the take function with list comprehension

您将如何使用列表理解来实现 take

目前我的方法:

take2 :: (Num i, Ord i) => i -> [a] -> [a]
take2 n xs = [x | x <- xs, [x..n]]

我们可以在这里使用 zip 方法,并枚举元素和索引,例如:

take2 :: (Num i, Enum i) => i -> [a] -> [a]
take2 n xs = [x | (x, _) <- zip xs [1..n]]

或使用 ParallelListComp 扩展名:

{-# LANGUAGE ParallelListComp #-}

take2 :: (Num i, Enum i) => i -> [a] -> [a]
take2 n xs = [x | x <- xs | _ <- [1..n]]

但实际上 take 可能不是一个首先适合列表理解的函数。

列表推导式不适合 take 函数的根本原因是:

take 函数 n 个元素之后停止参数列表的计算

但是列表推导式总是计算生成器中列表的所有元素。 Haskell中没有break-statement。


您可以在列表理解中使用之前或之后使用一些技巧来截断列表,但这样做没有实际意义。这类似于首先使用普通 take 截断列表,然后使用列表推导式 return 结果。

没有列表理解

take' :: Int -> [Int] -> [Int]
take' _ [] = []
take' _ [x] = [x]
take' n all@(x : xs)
        | (n > length all) = error "Index too large"
        | (n == length all) = all
        | (n == 0) = []
        | (n < length all) =  x : [] ++ (take' (n-1) xs)
take' :: Int -> [a] -> [a]
take' n xs = [xs !! i | i <- [0..n-1]]