Python отложено выполнение - PullRequest
3 голосов
/ 27 июня 2011

Для реализации потоков в виде списков с задержкой в Лиспе рекомендуется использовать макросы Lisp.

(defmacro cons-stream (a b)
   (cons ,a (delay ,b)))

(defmacro delay (expr)
  `(memo-proc (lambda () ,expr)))

Что бы Python и Perl могли сделать так жевещь?

РЕДАКТИРОВАТЬ.Можно ли использовать такую ​​классную конструкцию как потоки

(define primes (sieve (integers-starting-from 2)))

в таких языках, как Python и Perl

Ответы [ 4 ]

5 голосов
/ 28 июня 2011

В Python самой близкой структурой, вероятно, будет выражение генератора.

В Perl нет собственного отложенного списка, но язык предоставляет все примитивы, необходимые для его создания.Я написал ленивую библиотеку списков с именем List :: Gen , которая доступна на CPAN.

use List::Gen '*';

my $primes = <2..>->filter(\&is_prime);  # where you provide &is_prime

say "@$primes[0..10]";  # lazily finds the first 11 primes

бит <2..> может быть записан подробно как range(2, 9**9**9)

4 голосов
/ 28 июня 2011

Perl

Рунриг предложил методы из превосходного Марка Доминуса Perl высшего порядка .Используя Потоковый модуль из свободно доступного примера кода HOP, сито Эратосфена имеет вид

#! /usr/bin/env perl

use strict;
use warnings;

use Stream qw/ filter head node promise show tail upfrom /;

use subs 'sieve';  # no parens on recursive calls
sub sieve {
  my($s) = @_;
  my $n = head $s;
  node $n, promise { sieve filter { $_[0] % $n != 0 } tail $s };
}

sub primes { sieve upfrom 2 }

show primes, 10;

Выход:

$ ./primes
2 3 5 7 11 13 17 19 23 29

Python

Заимствованиекод из gist от alexbowe , сито в Python с использованием потоков:

#! /usr/bin/env python

null_stream = (None, None)

def reduce(f, result, stream):
    if stream is null_stream: return result
    return reduce(f, f(result, head(stream)), tail(stream))

def take(N, stream):
    if N <= 0 or stream is null_stream: return null_stream
    return (head(stream), lambda: take(N-1, tail(stream)))

def filter(pred, stream):
    if stream is null_stream: return null_stream
    if pred(head(stream)):
        return (head(stream), lambda: filter(pred, tail(stream)))
    return filter(pred, tail(stream))

def integers_from(N): return (N, lambda: integers_from(N+1))
def head((H, _)): return H
def tail((_, T)): return T()
def to_array(stream): return reduce(lambda a, x: a + [x], [], stream)

def sieve(stream):
    if stream is null_stream: return null_stream
    h = head(stream)
    return (h, lambda: sieve(filter(lambda x: x%h != 0, tail(stream))))

def primes(): return sieve(integers_from(2))

print to_array(take(10, primes()))

Вывод:

$ ./prymes 
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29]

Другие возможности

В некоторыхязыки, шаблон потока невидим.Ленивая оценка - это, например, особенность Haskell, поэтому вы можете определить primes как

primes = sieve [2 ..]
  where sieve (x:xs) =
          let remains = filter (not . isMultipleOf x) xs
          in x : sieve remains
        isMultipleOf a b = b `mod` a == 0
3 голосов
/ 27 июня 2011

В Perl вы бы использовали анонимные подпрограммы (например, лямбда LISP). Есть множество примеров в главе 6 из Perl высшего порядка

1 голос
/ 27 июня 2011

Хотя трудно сказать, что вы на самом деле хотите, так как многие вещи немного различаются в разных языках, его эквивалент Python, который вы ищете, это, вероятно, генератор , который это разновидность функции, которую можно попросить произвести следующее значение, а затем приостановить себя. Ранее они рассматривались в (например) Для чего вы можете использовать функции генератора Python? , и существует множество примеров и учебных пособий по ним, доступных в других местах - например, http://www.dabeaz.com/generators/index.html

...