Aşağıdaki kod sonsuz bir ağaç oluşturur, aynı zamanda tüm alt ağaçların bir önbelleğini oluşturur, böylece hiçbir yinelenen alt ağaç oluşturulmaz. Yinelenen alt ağaçların ortadan kaldırılmasının gerekçesi, satranç gibi oyunların devlet ağaçlarına uygulanmasıdır: Biri, iki hamlinin sırasını değiştirerek aynı oyun durumunda olabilir. Oyun ilerledikçe, erişilemeyen haller belleğe devam etmemelidir. Bu problemi zayıf işaretçiler kullanarak çözebileceğimi düşündüm. Ne yazık ki zayıf işaretçiler kullanmak bizi IO Monad'a getiriyor ve bu, bu kodun daha fazla sona ermeyeceği şekilde yeterli/tüm tembelliği yok etmiş görünüyor.Haskell zayıf göstergelerin önbelleği ile çift eleme ile sonsuz bir ağaç nasıl oluşturulur
Sorum şu ki: Yinelenen alt simgeler (ve bellek sızıntısı olmadan) olmadan tembel (oyun durumu) ağacının verimli bir şekilde üretilmesi mümkün mü?
{-# LANGUAGE RecursiveDo #-}
import Prelude hiding (lookup)
import Data.Map.Lazy (Map, empty, lookup, insert)
import Data.List (transpose)
import Control.Monad.State.Lazy (StateT(..))
import System.Mem.Weak
import System.Environment
type TreeCache = Map Integer (Weak NTree)
data Tree a = Tree a [Tree a]
type Node = (Integer, [Integer])
type NTree = Tree Node
getNode (Tree a _) = a
getVals = snd . getNode
makeTree :: Integer -> IO NTree
makeTree n = fst <$> runStateT (makeCachedTree n) empty
makeCachedTree :: Integer -> StateT TreeCache IO NTree
makeCachedTree n = StateT $ \s -> case lookup n s of
Nothing -> runStateT (makeNewTree n) s -- makeNewTree n s
Just wt -> deRefWeak wt >>= \mt -> case mt of
Nothing -> runStateT (makeNewTree n) s
Just t -> return (t,s)
makeNewTree :: Integer -> StateT TreeCache IO NTree
makeNewTree n = StateT $ \s -> mdo
wt <- mkWeak n t Nothing
(ts, s') <- runStateT
(mapM makeCachedTree $ children n)
(insert n wt s)
let t = Tree (n, values n $ map getVals ts) ts
return (t, s')
children n = let bf = 10 in let hit = 2 in [bf*n..bf*n+bf+hit-1]
values n [] = repeat n
values n nss = n:maximum (transpose nss)
main = do
args <- getArgs
let n = read $ head args in
do t <- makeTree n
if length args == 1 then putStr $ show $ take (fromInteger n) $ getVals t else putStr "One argument only!!!"
Zayıf işaretçilerin (dolayısıyla "IO") gerekli olacağını düşünmüyorum. Örneğin, 'Data.Seq', akıllı kod kullanarak dahili paylaşımı en üst düzeye çıkarmak için büyük uzunluklara gider: https://hackage.haskell.org/package/containers-0.5.7.1/docs/src/Data.Sequence.html#applicativeTree – cdk
@cdk, Nerede/nasıl yaptığını bulamıyorum. Yorumda "Özel not: Kimlik uzmanlığı, düğümlenmeyi otomatik olarak gerçekleştirir, sonuçta oluşan ağacın/O (log n) /" için bellek kullanımını azaltır, kodun paylaşımı açıkça uygulamadığı, ancak derleyici optimizasyonları olduğu ima edilir. Belli bir uzmanlık için bunun olmasını sağlayın (diğer durumlarda bunun gerçekleşmeyeceğini ima ederek). Data.Seq'in nasıl paylaştığını ve bunun bana nasıl yardımcı olacağını biraz daha açıklayabilir misiniz? – hkBst
@hkBst, bu yorum yanıltıcıdır ve bir sonraki sürümde açıklığa kavuşturmak için onu düzenlemeyi deneyeceğim. “Identity” için derleyici uzmanlığı, sabit faktörleri iyileştirmekten başka bir şey yapmaz. Gerçekten anlamı şudur: * Kimlik ile kullanıldığında * çok fazla paylaşım var. – dfeuer