SORU
13 Mayıs 2009, ÇARŞAMBA


Java derin özyineleme gelen yığını taşmaları?

Fonksiyonel diller ile biraz tecrübe ettikten sonra, daha fazla Java özyineleme kullanmaya başladım Ama dili nispeten sığ bir ara 1000 yığını gibi görünüyor.

Bir şekilde bu çağrı büyük bir yığın yapmak var mı? Aramalar derin milyonlarca işlevleri yapabilir miyim gibi Ayrık gibi mi?

Daha fazla Project Euler problem, bunu yaptığımda fark ettim.

Teşekkürler.

CEVAP
14 Mayıs 2009, PERŞEMBE


Artan boyutu sadece geçici bir bandaj olarak hizmet verecek yığını. Diğerleri belirttiği gibi, gerçekten ne istediğini kuyruk Ara ortadan kaldırılması ve Java çeşitli nedenlerle bu yok. Ancak, eğer isterseniz hile yapabilir.

Elinde kırmızı hap mı? TAMAM, bu taraftan lütfen.

Hangi exchange yığın yığın vardır. Bir özyinelemeli bir işlev içinde arama yapmak yerine, örneğin, bir dönüş vartembel datastructurebu değerlendirildiğinde çağrısı yapar. Sonra gevşeyebilirsiniz "yığın" Java ile inşa. Bir örnekle göstereyim. Düşünün bu Haskell kodu:

map :: (a -> b) -> [a] -> [b]
map _ [] = []
map f (x:xs) = (f x) : map f xs

Bu işlev hiçbir zaman listenin kuyruk değerlendirir unutmayın. Yani işlevi aslında özyinelemeli arama yapmanıza gerek yok. Haskell, aslında bir döndürürthunkeğer gerekli olursa diye adlandırılan kuyruk, için. Aynı şeyi Java (Functional Java sınıfları kullanır) yapabiliriz:

public <B> Stream<B> map(final F<A, B> f, final Stream<A> as)
  {return as.isEmpty()
     ? nil()
     : cons(f.f(as.head()), new P1<Stream<A>>()
         {public Stream<A> _1()
           {return map(f, as.tail);}});}

Not Stream<A> oluşur bir değer türü A ve bir değer yazın P1 gibi bir thunk verir, gerisi akışı zaman _1() denir. Kesinlikle özyineleme gibi görünüyor olsa da, göster özyinelemeli çağrı yapılmış değil, ama Akış datastructure bir parçası haline gelir.

Bu o zaman normal olan için inşa çözülmemiş olabilir.

for (Stream<B> b = bs; b.isNotEmpty(); b = b.tail()._1())
  {System.out.println(b.head());}

Project Euler bahsettiğin beri burada başka bir örnek. Bu program karşılıklı özyinelemeli işlevleri kullanır ve yığın, hatta aramaları milyonlarca darbe değildir:

import fj.*; import fj.data.Natural;
import static fj.data.Enumerator.naturalEnumerator;
import static fj.data.Natural.*; import static fj.pre.Ord.naturalOrd;
import fj.data.Stream; import fj.data.vector.V2;
import static fj.data.Stream.*; import static fj.pre.Show.*;

public class Primes
  {public static Stream<Natural> primes()
    {return cons(natural(2).some(), new P1<Stream<Natural>>()
       {public Stream<Natural> _1()
         {return forever(naturalEnumerator, natural(3).some(), 2)
                 .filter(new F<Natural, Boolean>()
                   {public Boolean f(final Natural n)
                      {return primeFactors(n).length() == 1;}});}});}

   public static Stream<Natural> primeFactors(final Natural n)
     {return factor(n, natural(2).some(), primes().tail());}

   public static Stream<Natural> factor(final Natural n, final Natural p,
                                        final P1<Stream<Natural>> ps)
     {for (Stream<Natural> ns = cons(p, ps); true; ns = ns.tail()._1())
          {final Natural h = ns.head();
           final P1<Stream<Natural>> t = ns.tail();
           if (naturalOrd.isGreaterThan(h.multiply(h), n))
              return single(n);
           else {final V2<Natural> dm = n.divmod(h);
                 if (naturalOrd.eq(dm._2(), ZERO))
                    return cons(h, new P1<Stream<Natural>>()
                      {public Stream<Natural> _1()
                        {return factor(dm._1(), h, t);}});}}}

   public static void main(final String[] a)
     {streamShow(naturalShow).println(primes().takeWhile
       (naturalOrd.isLessThan(natural(Long.valueOf(a[0])).some())));}}

Yığın yığın değişimi için yapabileceğiniz başka bir şey kullanmaktırbirden çok iş parçacığı. Fikri özyinelemeli arama yapmak yerineyeni bir iş parçacığı iptal, elini thunk yapar ve geçerli iş parçacığı işlevi çıkış izin veren bir thunk oluşturun.Bu Yığınsız Python gibi şeyler arkasındaki fikir.

Aşağıdaki Java buna bir örnek. Biraz donuk import static maddeler olmadan bakmak için özür dilerim: see it here in context

public static <A, B> Promise<B> foldRight(final Strategy<Unit> s,
                                          final F<A, F<B, B>> f,
                                          final B b,
                                          final List<A> as)
  {return as.isEmpty()
     ? promise(s, P.p(b))
     : liftM2(f).f
         (promise(s, P.p(as.head()))).f
         (join(s, new P1<Promise<B>>>()
            {public Promise<B> _1()
              {return foldRight(s, f, b, as.tail());}}));}

Strategy<Unit> s tarafından desteklenen bir iş parçacığı havuzu, promise fonksiyonu eller bir thunk için iş parçacığı havuzu, dönen bir Promise, yani çok fazla gibi java.util.concurrent.Future, sadece daha iyi. See here. noktasının yöntemiEy doğru(1) doğru-özyinelemeli bir datastructure yığın çekiliyornormalde kuyruk-Ara ortadan kaldırılması gerekir., Etkili TCE, bazı karmaşıklığı karşılığında achived ettik. Aşağıdaki gibi: bu fonksiyonu çağırırsınız

Strategy<Unit> s = Strategy.simpleThreadStrategy();
int x = foldRight(s, Integers.add, List.nil(), range(1, 10000)).claim();
System.out.println(x); // 49995000

Bu son tekniği çok iyi olmayan özyineleme için çalıştığını unutmayın. Yani, sürekli çalıştırmak kuyruk aramaları yok mu, o bile algoritmaları yığını olacak.

Yapabileceğiniz başka bir şey denilen bir tekniği kullanırtarmbolin üstünde zıplamak. Bir trambolin ile basamaklı bir hesaplama, veri yapısı olarak şeyleşiyor. Functional Java library etkili kuyruk bir ara içine herhangi bir işlev çağrısı açmanıza olanak tanıyan yazdım Trampoline veri türü içerir. Örnek olarak 31**

public final <B> Trampoline<B> foldRightC(final F2<A, B, B> f, final B b)
  {return Trampoline.suspend(new P1<Trampoline<B>>()
    {public Trampoline<B> _1()
      {return isEmpty()
         ? Trampoline.pure(b)
         : tail().foldRightC(f, b).map(f.f(head()));}});}

Aynı prensip olarak kullanarak birden çok iş parçacığı, dışında yerine çağırarak her adımda kendi iş parçacığı, biz inşa her adımda öbek, çok gibi kullanma Stream, ve sonra biz çalıştırmak tüm adımları tek bir döngü ile Trampoline.run.

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • Ben Schoon

    Ben Schoon

    23 Kasım 2012
  • kidrauhl

    kidrauhl

    15 Ocak 2007
  • MagicofRahat

    MagicofRahat

    13 Temmuz 2007