Jbapple'ın mükemmel cevabına dayanarak replicate
, bunun yerine replicateA
( replicate
üzerine kurulu) kullanarak , aşağıdakileri buldum:
--Unlike fromList, one needs the length explicitly.
myFromList :: Int -> [b] -> Seq b
myFromList l xs = flip evalState xs $ Seq.replicateA l go
where go = do
(y:ys) <- get
put ys
return y
myFromList
(biraz daha verimli bir versiyonda) zaten tanımlanmış veData.Sequence
türlerin sonuçları olan parmak ağaçlarının yapımında dahili olarak kullanılmaktadır .
Genel olarak, sezgi replicateA
basittir. applicativeTree işlevinin replicateA
üzerine kurulmuştur . büyüklüğünde bir ağaç parçası alır ve bunun kopyalarını içeren dengeli bir ağaç üretir . 8'e kadar olan durumlar (tek bir parmak) sabit kodlanmıştır. Bunun üzerindeki her şey ve kendini tekrar tekrar çağırır. "Uygulanabilir" eleman, basitçe, yukarıdaki kod durumunda, durumun iş parçacığı oluşturma efektleri ile ağacın yapısına serpiştirmesidir.applicativeTree
m
n
n
Deep
go
Çoğaltılır fonksiyonu, sadece, mevcut durumunu alır üst bir eleman açılır ve geri kalan yerini alan bir işlemdir. Böylece her çağrıda girdi olarak verilen listeden daha aşağı iner.
Biraz daha somut notlar
main = print (length (show (Seq.fromList [1..10000000::Int])))
Bazı basit testlerde, bu ilginç bir performans dengesi sağladı. Yukarıdaki ana işlev myFromList ile olduğundan yaklaşık 1/3 daha düşüktü fromList
. Öte yandan, myFromList
2 MB'lık sabit bir yığın fromList
kullanılırken , standart 926MB'a kadar kullanıldı. Bu 926MB, tüm listeyi bir kerede bellekte tutmaya ihtiyaç duymasından kaynaklanıyor. Bu arada, çözüm myFromList
tembel bir akış tarzında yapıyı tüketebilir. Hız sorunu, myFromList
kabaca iki kat daha fazla tahsis edilmesi gerektiği gerçeğinden kaynaklanmaktadır (çift devlet inşasının / çiftinin inşası / imhası sonucu)fromList
. Bu tahsisleri CPS ile dönüştürülmüş bir devlet monadına geçerek ortadan kaldırabiliriz, ancak bu, herhangi bir zamanda çok daha fazla belleğe tutunmasına neden olur, çünkü tembellik kaybı listenin akışsız bir şekilde geçmesini gerektirir.
Öte yandan, tüm diziyi bir gösteri ile zorlamak yerine, sadece kafa veya son elemanı çıkarmak için hareket ediyorum, myFromList
hemen daha büyük bir kazanç sunuyorum - kafa elemanını çıkarmak neredeyse anında ve son elemanı çıkarmak 0.8s. . Bu arada, standart ile fromList
, kafa veya son elemanın çıkarılması ~ 2.3 saniye sürer.
Tüm bunlar detay ve saflık ve tembellikten kaynaklanıyor. Mutasyon ve rastgele erişime sahip bir durumda, replicate
çözümün kesinlikle daha iyi olduğunu hayal ediyorum .
Ancak, yeniden yazmak için bir yol olup olmadığını sorusunu zam yapar applicativeTree
böyle myFromList
kesinlikle daha verimlidir. Sorun, bence, uygulanabilir eylemlerin ağaçtan doğal olarak geçildiğinden farklı bir sırayla yürütüldüğü, ancak bunun nasıl çalıştığı veya bunu çözmenin bir yolu olup olmadığı üzerinde tam olarak çalışmadım.