等价于具有停止条件的生成器的 Haskell
Equivalent in Haskell of generator with stopping condition
假设我想在 Haskell 中构建一个列表 iterate step x0
,但包含终止条件。所以在 Python 中,这将是 list(my_gen)
,例如
def my_gen():
x = x0
while not done(x):
x = step(x)
yield x
(编辑: 如果我想包含 x0
,这应该在循环之前有一个额外的 yield x
。)
一种方法是写我自己的 takeWhileInclusive 然后说
takeWhileInclusive (not . done) . iterate step x0
这是 Haskell-y 方式(或 a Haskell-y 方式)来完成这个吗?当 done x
为真时尝试为 step x
添加一些标记值然后使用 takeWhile
.
似乎是不自然的
特别是我想到了 LeetCode 上的 container with most water problem,并用
之类的东西解决了它
maxWith volume . smartSteps (0, n)
where smartSteps = takeWhileInclusive (\(i,j) -> j - i > 1) . iterate step
和 step
增加 i
或减少 j
(或两者),根据哪个索引具有更高的行。
当然这里只使用 takeWhile
j > i 会很容易,但我想想想我将如何处理没有自然的“你走得太远”条件的情况,只是“你完成了”条件。
编辑: 这个问题已被标记为重复(我在问题中链接到的 question),但事实并非如此。问题不是如何写 takeWhileInclusive
,实际上这个问题明确地把 takeWhileInclusive
当作给定的。它是关于如何完成一项可能使用或不使用 takeWhileInclusive
.
的任务
是的,这是一种 Haskell-y 方式。
另一种 Haskell-y 方式(或 Haskell-y 方式来实现 takeWhileInclusive
)是稍后一步压缩 iterate
d 值。
myGen done step = map snd . takeWhile (not . done . fst) . ap zip tail . iterate step
N.B。与 iterate
不同(但与 my_gen
相似)这不会发出初始 x
值作为步骤之一。
您可以使用unfoldr
生成序列:
unfoldr (\x -> if done x then Nothing else Just (x, step x)) x0
例如,
> import Data.List
> step = (+1)
> done = (> 10)
> x0 = 0
> unfoldr (\x -> if done x then Nothing else Just (x, step x)) x0
[0,1,2,3,4,5,6,7,8,9,10]
unfoldr
在 x0
上调用它的函数开始。当函数returnsNothing
、unfoldr
停止时。当函数 returns Just (x, y)
时,它将 x
附加到结果并在 y
.
上再次调用该函数
将您的生成器与 unfoldr
的 Python 实现进行比较:
def unfoldr(f, x):
while True:
if (y := f(x)) is None:
return
else:
yield y[0]
x = y[1]
list(unfoldr(lambda x: None if done(x) else (x, step(x)), x0))
你可以定义
takeUntil done xs =
foldr (\x r -> if done x then [x] else x : r) [] xs
然后像
一样使用它
takeUntil done $ iterate step x0
例如takeUntil (> 9) [1..] == [1..10]
.
使用 foldr
指定最终元素很容易(如此处所示),但使用编码“变形”的 unfoldr
更麻烦,用空 列表作为哨兵。使用“同构”可以指定非空尾,这似乎是完成此任务的合适工具。
假设我想在 Haskell 中构建一个列表 iterate step x0
,但包含终止条件。所以在 Python 中,这将是 list(my_gen)
,例如
def my_gen():
x = x0
while not done(x):
x = step(x)
yield x
(编辑: 如果我想包含 x0
,这应该在循环之前有一个额外的 yield x
。)
一种方法是写我自己的 takeWhileInclusive 然后说
takeWhileInclusive (not . done) . iterate step x0
这是 Haskell-y 方式(或 a Haskell-y 方式)来完成这个吗?当 done x
为真时尝试为 step x
添加一些标记值然后使用 takeWhile
.
特别是我想到了 LeetCode 上的 container with most water problem,并用
之类的东西解决了它maxWith volume . smartSteps (0, n)
where smartSteps = takeWhileInclusive (\(i,j) -> j - i > 1) . iterate step
和 step
增加 i
或减少 j
(或两者),根据哪个索引具有更高的行。
当然这里只使用 takeWhile
j > i 会很容易,但我想想想我将如何处理没有自然的“你走得太远”条件的情况,只是“你完成了”条件。
编辑: 这个问题已被标记为重复(我在问题中链接到的 question),但事实并非如此。问题不是如何写 takeWhileInclusive
,实际上这个问题明确地把 takeWhileInclusive
当作给定的。它是关于如何完成一项可能使用或不使用 takeWhileInclusive
.
是的,这是一种 Haskell-y 方式。
另一种 Haskell-y 方式(或 Haskell-y 方式来实现 takeWhileInclusive
)是稍后一步压缩 iterate
d 值。
myGen done step = map snd . takeWhile (not . done . fst) . ap zip tail . iterate step
N.B。与 iterate
不同(但与 my_gen
相似)这不会发出初始 x
值作为步骤之一。
您可以使用unfoldr
生成序列:
unfoldr (\x -> if done x then Nothing else Just (x, step x)) x0
例如,
> import Data.List
> step = (+1)
> done = (> 10)
> x0 = 0
> unfoldr (\x -> if done x then Nothing else Just (x, step x)) x0
[0,1,2,3,4,5,6,7,8,9,10]
unfoldr
在 x0
上调用它的函数开始。当函数returnsNothing
、unfoldr
停止时。当函数 returns Just (x, y)
时,它将 x
附加到结果并在 y
.
将您的生成器与 unfoldr
的 Python 实现进行比较:
def unfoldr(f, x):
while True:
if (y := f(x)) is None:
return
else:
yield y[0]
x = y[1]
list(unfoldr(lambda x: None if done(x) else (x, step(x)), x0))
你可以定义
takeUntil done xs =
foldr (\x r -> if done x then [x] else x : r) [] xs
然后像
一样使用它takeUntil done $ iterate step x0
例如takeUntil (> 9) [1..] == [1..10]
.
使用 foldr
指定最终元素很容易(如此处所示),但使用编码“变形”的 unfoldr
更麻烦,用空 列表作为哨兵。使用“同构”可以指定非空尾,这似乎是完成此任务的合适工具。