我正在努力解决如何使Haskell中的有状态计算懒惰地生成结果的一般问题。E、 g.下面的简单算法可以在Python的生成器工具的帮助下表示为有状态但“懒惰”的计算,只执行到达下一个yield
语句所需的步骤,然后将控制流返回给调用者,直到请求下一个元素:
def solveLP(vmax0, elems):
elem_true_ixs = [ [ ei for ei, b in enumerate(row) if b ] for row in elems ]
return go(vmax0, elem_true_ixs)
def go(vmax, mms):
if not mms:
yield []
else:
for ei in mms[0]:
maxcnt = vmax[ei]
if not maxcnt > 0:
continue
vmax[ei] = maxcnt-1 # modify vmax vector in-place
for es in go(vmax, mms[1:]):
# note: inefficient vector-concat operation
# but not relevant for this question
yield [ei]+es
vmax[ei] = maxcnt # restore original vmax state
for sol in solveLP([1,2,3],[[True,True,False],[True,False,True]]):
print sol
# prints [0,2], [1,0], and [1,2]
这可以很容易地转换为懒惰的Haskell计算(例如,当m
专门化为Logic
或{
…但是我希望能够更接近原始的Python实现,方法是使用可变向量,并在适当的地方修改一个vmax0
向量(因为我只需要增加/减少一个元素,复制整个向量来替换单个元素是一个相当大的开销,向量变得越长);请注意,这只是我尝试实现的一类算法的一个玩具示例
所以我的问题是——假设有一种方法可以实现这一点——我如何在第一个单子中表达这样一个有状态的算法,同时还能在计算过程中一产生结果就把结果返回给调用者呢?我尝试过通过monad transformers将ST monad与list monad相结合,但是我不知道如何使它工作。。。在
只需使用lazy-ST。在Haskell中,普通的旧列表与Python生成器基本相同,因此我们将返回一个结果列表(其中结果是
[Int]
)。下面是Python代码的音译:尝试例如
solveLP [1,undefined,3] [[True,True,False],[True,False,True]]
来查看它是否确实懒洋洋地返回结果。在让我们对Python代码进行更直接的翻译。您在Python中使用协同程序,那么为什么不在Haskell中使用协同程序呢?还有可变向量的问题;请参阅下面的详细信息。在
首先,吨进口:
下面是一些实用程序定义,它们让我们将协同程序视为在Python中的行为,或多或少:
^{pr2}$现在我们需要能够以某种方式使用
STVector
s。您说您希望使用lazyST,并且对STVector
s的预定义操作只为strictST定义,因此我们需要制作一些包装函数。我不喜欢为这样的东西做操作符,但是如果你真的想让代码变成python(例如,$=
代表writeLazy
或其他任何东西;你需要以某种方式处理索引投影,但无论如何,它可能看起来更好)。在所有的工具都在这里,我们来翻译一下算法:
遗憾的是,没有人费心为}在这里不可用。但这可能不是你想要的,因为在某些/大多数单子中停顿时会产生错误。当然,我们还需要
Coroutine
定义MonadPlus
,因此{lift
将ST
monad中完成的所有操作从Coroutine
monad中取出;这是一个小麻烦。在这就是所有的代码,所以你可以简单地运行它:
list
变量是纯变量,是惰性生成的。在我有点累了,所以如果有什么不明白的话,请不要犹豫地指出。在
我现在还太早,不能及时理解你的算法。但如果我没看错问题,你可以用lazy ST。这里有个小例子:
它正是从维护其状态的ST操作创建一个延迟结果流。在
相关问题 更多 >
编程相关推荐