生成无限列表 [0, 1, -1, 2, -2, ... in Haskell
Produce the infinite list [0, 1, -1, 2, -2, ... in Haskell
所以假设我们要在 Haskell.
中生成列表 [0, 1, -1, 2, -2, ...
完成此任务最优雅的方法是什么?
我想到了这个解决方案:
solution = [0] ++ foldr (\(a,b) c->a:b:c) [] zip [1..] $ map negate [1..]
但我相信一定有更好的方法。
这似乎是理解的对象:
solution = 0 : [y | x <- [1..], y <- [x, -x]]
怎么样
concat (zipWith (\x y -> [x, y]) [0, -1 ..] [1 ..])
或
concat (transpose [[0, -1 ..], [1 ..]])
?
和iterate
也许更优雅的方法是使用 iterate :: (a -> a) -> a -> [a]
和一个每次都生成下一个项目的函数。例如:
solution = iterate nxt 0
where nxt i | i > 0 = -i
| otherwise = 1-i
或者我们可以用 if
-then
-else
:
内联
solution = iterate (\i -> if i > 0 then -i else 1-i) 0
或者我们可以将布尔值转换为整数,如@melpomene 所说,使用 fromEnum
,然后使用它来将 1
或 0
添加到答案中,因此:
solution = iterate (\i -> fromEnum (i < 1)-i) 0
哪个更省点:
import Control.Monad(ap)
solution = iterate (ap subtract (fromEnum . (< 1))) 0
和(<**>)
我们还可以使用 applicate 中的 <**>
运算符每次生成数字的正负变体,例如:
import Control.Applicative((<**>))
solution = 0 : ([1..] <**> [id, negate])
怎么样:
tail $ [0..] >>= \x -> [x, -x]
考虑一下,我认为使用 nub
而不是 tail
会更优雅。
您也可以在这里使用concatMap
代替foldr
,并将map negate [1..]
替换为[0, -1..]
:
solution = concatMap (\(a, b) -> [a, b]) $ zip [0, -1..] [1..]
如果您想使用 negate
,那么这是另一个选项:
solution = concatMap (\(a, b) -> [a, b]) $ (zip . map negate) [0, 1..] [1..]
另一种原始解决方案
alt = 0 : go 1
where go n = n : -n : go (n+1)
晚会迟到了,但这也行
solution = [ (1 - 2 * (n `mod` 2)) * (n `div` 2) | n <- [1 .. ] ]
只是因为没有人说:
0 : concatMap (\x -> [x,-x]) [1..]
所以假设我们要在 Haskell.
中生成列表[0, 1, -1, 2, -2, ...
完成此任务最优雅的方法是什么?
我想到了这个解决方案:
solution = [0] ++ foldr (\(a,b) c->a:b:c) [] zip [1..] $ map negate [1..]
但我相信一定有更好的方法。
这似乎是理解的对象:
solution = 0 : [y | x <- [1..], y <- [x, -x]]
怎么样
concat (zipWith (\x y -> [x, y]) [0, -1 ..] [1 ..])
或
concat (transpose [[0, -1 ..], [1 ..]])
?
和iterate
也许更优雅的方法是使用 iterate :: (a -> a) -> a -> [a]
和一个每次都生成下一个项目的函数。例如:
solution = iterate nxt 0
where nxt i | i > 0 = -i
| otherwise = 1-i
或者我们可以用 if
-then
-else
:
solution = iterate (\i -> if i > 0 then -i else 1-i) 0
或者我们可以将布尔值转换为整数,如@melpomene 所说,使用 fromEnum
,然后使用它来将 1
或 0
添加到答案中,因此:
solution = iterate (\i -> fromEnum (i < 1)-i) 0
哪个更省点:
import Control.Monad(ap)
solution = iterate (ap subtract (fromEnum . (< 1))) 0
和(<**>)
我们还可以使用 applicate 中的 <**>
运算符每次生成数字的正负变体,例如:
import Control.Applicative((<**>))
solution = 0 : ([1..] <**> [id, negate])
怎么样:
tail $ [0..] >>= \x -> [x, -x]
考虑一下,我认为使用 nub
而不是 tail
会更优雅。
您也可以在这里使用concatMap
代替foldr
,并将map negate [1..]
替换为[0, -1..]
:
solution = concatMap (\(a, b) -> [a, b]) $ zip [0, -1..] [1..]
如果您想使用 negate
,那么这是另一个选项:
solution = concatMap (\(a, b) -> [a, b]) $ (zip . map negate) [0, 1..] [1..]
另一种原始解决方案
alt = 0 : go 1
where go n = n : -n : go (n+1)
晚会迟到了,但这也行
solution = [ (1 - 2 * (n `mod` 2)) * (n `div` 2) | n <- [1 .. ] ]
只是因为没有人说:
0 : concatMap (\x -> [x,-x]) [1..]