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.applicativeTreemnnDeep
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, myFromList2 MB'lık sabit bir yığın fromListkullanı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 myFromListtembel bir akış tarzında yapıyı tüketebilir. Hız sorunu, myFromListkabaca 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, myFromListhemen 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 applicativeTreeböyle myFromListkesinlikle 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.