使用列表理解实现 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]]
您将如何使用列表理解来实现 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]]