Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/358.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/svg/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
SICP“;“作为信号的流”;用Python_Python_Stream_Sicp - Fatal编程技术网

SICP“;“作为信号的流”;用Python

SICP“;“作为信号的流”;用Python,python,stream,sicp,Python,Stream,Sicp,我发现了一些在Python中实现类SICP流的好例子(,)。但是我仍然不知道如何处理像SICP 3.5.3中的积分这样的例子 在那里找到的方案代码为 (define (integral integrand initial-value dt) (define int (cons-stream initial-value (add-streams (scale-stream integrand dt)

我发现了一些在Python中实现类SICP流的好例子(,)。但是我仍然不知道如何处理像SICP 3.5.3中的
积分
这样的例子

在那里找到的方案代码为

(define (integral integrand initial-value dt)
  (define int
    (cons-stream initial-value
                 (add-streams (scale-stream integrand dt)
                              int)))
  int)
关于这个问题,需要技巧的是返回的流
int
是根据自身定义的(即,流
int
用于流
int
的定义)


我相信Python可以有类似的表现力和简洁性。。。但不知道怎么做。所以我的问题是,Python中类似的stream-y构造是什么?(我所说的流是SICP中3.5的主题,但简单地说,是一种结构(如Python生成器),它返回不定长序列的连续元素,并且可以与诸如添加流和缩放流之类的操作组合和处理,这些操作尊重流的惰性特征。)阅读问题有两种方法。第一个问题很简单:如何使用流结构,可能是第二个结构中的流结构,但是使用递归定义?这是可以做到的,尽管在Python中有点笨拙

在Python中,可以表示循环数据结构,但不能直接表示。你不能写:

l = [l]
def integral(integrand,initial_value,dt):
    int_rec = cons_stream(initial_value,
                          add_streams(scale_stream(integrand,dt),
                                      int_rec))
    return int_rec
但你可以写:

l = [None]
l[0] = l
def integral(integrand,initial_value,dt):
    placeholder = Stream(initial_value,lambda : None)
    int_rec = cons_stream(initial_value,
                          add_streams(scale_stream(integrand,dt),
                                      placeholder))
    placeholder._compute_rest = lambda:int_rec
    return int_rec
同样,你不能写:

l = [l]
def integral(integrand,initial_value,dt):
    int_rec = cons_stream(initial_value,
                          add_streams(scale_stream(integrand,dt),
                                      int_rec))
    return int_rec
但你可以写:

l = [None]
l[0] = l
def integral(integrand,initial_value,dt):
    placeholder = Stream(initial_value,lambda : None)
    int_rec = cons_stream(initial_value,
                          add_streams(scale_stream(integrand,dt),
                                      placeholder))
    placeholder._compute_rest = lambda:int_rec
    return int_rec
请注意,我们需要笨拙地预先计算
占位符的第一个元素,然后只修复流其余部分的递归。但这一切都是可行的(与所有其他代码的适当定义一起——我将把它全部放在这个答案的底部)

然而,问题的第二部分似乎是问如何在Python中自然地做到这一点。您需要一个“Python中的类似stream-y构造”。显然,答案正是发电机。生成器自然会提供流概念的惰性评估。它的不同之处在于没有自然地递归表示,但Python不支持这种方式,正如我们将看到的,Scheme也不支持这种方式

换句话说,严格的流概念可以用Python表达(如链接和上面的内容),但惯用的方法是使用生成器

通过将流直接机械转换为生成器(但避免内置
int
),或多或少可以复制方案示例:

这里唯一棘手的事情是要认识到,您需要急切地调用递归使用
int\u rec
作为
add\u streams
的参数。调用它并不会让它开始产生值——它只会创建生成器,在需要时惰性地产生值

这对于小的被积函数非常有效,尽管它不是很适合python。Scheme版本通过优化尾部递归来工作-如果被积函数太长,Python版本将超过最大堆栈深度。因此,这在Python中并不真正合适

我认为,一个直接而自然的python版本应该是这样的:

def integral(integrand,initial_value,dt):
    value = initial_value
    yield value
    for x in integrand:
        value += dt * x
        yield value
这可以有效且正确地将
被积函数
惰性地视为一个“流”。然而,它使用迭代而不是递归来解包被积函数iterable,这更像Python的方式

在转向自然Python的过程中,我还删除了流组合函数——例如,将
add_streams
替换为
+=
。但如果我们想要一种中途之家的版本,我们仍然可以使用它们:

def accum(initial_value,a):
    value = initial_value
    yield value
    for x in a:
        value += x
        yield value

def integral_hybrid(integrand,initial_value,dt):
    for x in accum(initial_value,scale_stream(integrand,dt)):
        yield x
该混合版本使用来自方案的流组合,并且仅避免尾部递归。这仍然是pythonic,python在
itertools
模块中包含了各种其他很好的方法来使用iterables。正如你所说,他们都“尊重streams的懒惰性格”

最后,这里是第一个递归流示例的所有代码,大部分代码取自Berkeley参考:

class Stream(object):
        """A lazily computed recursive list."""
        def __init__(self, first, compute_rest, empty=False):
            self.first = first
            self._compute_rest = compute_rest
            self.empty = empty
            self._rest = None
            self._computed = False
        @property
        def rest(self):
            """Return the rest of the stream, computing it if necessary."""
            assert not self.empty, 'Empty streams have no rest.'
            if not self._computed:
                self._rest = self._compute_rest()
                self._computed = True
            return self._rest
        def __repr__(self):
            if self.empty:
                return '<empty stream>'
            return 'Stream({0}, <compute_rest>)'.format(repr(self.first))

Stream.empty = Stream(None, None, True)


def cons_stream(a,b):
    return Stream(a,lambda : b)

def add_streams(a,b):
    if a.empty or b.empty:
            return Stream.empty
    def compute_rest():
        return add_streams(a.rest,b.rest)
    return Stream(a.first+b.first,compute_rest)

def scale_stream(a,scale):
    if a.empty:
            return Stream.empty
    def compute_rest():
        return scale_stream(a.rest,scale)
    return Stream(a.first*scale,compute_rest)

def make_integer_stream(first=1):
      def compute_rest():
        return make_integer_stream(first+1)
      return Stream(first, compute_rest)

def truncate_stream(s, k):
        if s.empty or k == 0:
            return Stream.empty
        def compute_rest():
            return truncate_stream(s.rest, k-1)
        return Stream(s.first, compute_rest)

def stream_to_list(s):
        r = []
        while not s.empty:
            r.append(s.first)
            s = s.rest
        return r

def integral(integrand,initial_value,dt):
    placeholder = Stream(initial_value,lambda : None)
    int_rec = cons_stream(initial_value,
                          add_streams(scale_stream(integrand,dt),
                                      placeholder))
    placeholder._compute_rest = lambda:int_rec
    return int_rec

a = truncate_stream(make_integer_stream(),5)
print(stream_to_list(integral(a,8,.5)))
类流(对象):
“”“延迟计算的递归列表。”“”
def uu init uu(self,first,compute_rest,empty=False):
self.first=第一
self.\u compute\u rest=compute\u rest
self.empty=空
self.\u rest=无
self.\u computed=False
@财产
def休息(自我):
“”“返回流的其余部分,必要时进行计算。”“”
断言not self.empty,“空流无息”
如果不是自行计算的:
self.\u rest=self.\u compute\u rest()
self.\u computed=True
回归自我
定义报告(自我):
如果self.empty:
返回“”
返回'Stream({0},)'。格式(repr(self.first))
Stream.empty=流(无、无、真)
def cons_流(a、b):
回流(a,λ:b)
def添加_流(a、b):
如果a.empty或b.empty:
返回流为空
def compute_rest():
返回添加流(a.rest,b.rest)
返回流(a.first+b.first,compute\u rest)
def比例\ U流(a,比例):
如果a.empty:
返回流为空
def compute_rest():
返回比例\流(a.静止,比例)
回流(a.第一个*比例,计算剩余)
def生成整数流(第一个=1):
def compute_rest():
返回生成整数流(第一个+1)
返回流(首先,计算\u rest)
def截断_流(s,k):
如果s.empty或k==0:
返回流为空
def compute_rest():
返回截断流(s.rest,k-1)
返回流(s.first,compute_rest)
def流到列表:
r=[]
虽然不是空的:
r、 附加(s.first)
s=s.rest
返回r
def积分(被积函数,初始_值,dt):
占位符=流(初始值,λ:无)
int_rec=cons_流(初始值,
添加_流(标度_流(被积函数,dt),
占位符)
占位符.\u compute\u rest=lambda:int\u rec
返回整数记录
A.