मैं आपके प्रश्न को हल करने के लिए तीन अलग-अलग चाल का उपयोग करूंगा।
- छल 1: फ़ाइल नाम पेड़ traversing के साथ समवर्ती स्ट्रीम करने के लिए
pipes
पुस्तकालय का उपयोग करें।
- ट्रिक 2:
StateT (Seq FilePath)
ट्रांसफॉर्मर का उपयोग चौड़ाई-पहले ट्रैवर्सल प्राप्त करने के लिए करें।
- ट्रिक 3: लूप और बाहर निकलने के दौरान मैन्युअल रिकर्सन से बचने के लिए
MaybeT
ट्रांसफॉर्मर का उपयोग करें।
निम्नलिखित कोड इन तीन चालों को एक मोनड ट्रांसफॉर्मर स्टैक में जोड़ता है।
import Control.Monad
import Control.Monad.Trans
import Control.Monad.Trans.Maybe
import Control.Monad.State.Lazy
import Control.Pipe
import Data.Sequence
import System.FilePath.Posix
import System.Directory
loop :: (Monad m) => MaybeT m a -> m()
loop = liftM (maybe() id) . runMaybeT . forever
quit :: (Monad m) => MaybeT m a
quit = mzero
getUsefulContents :: FilePath -> IO [FilePath]
getUsefulContents path
= fmap (filter (`notElem` [".", ".."])) $ getDirectoryContents path
permissible :: FilePath -> IO Bool
permissible file
= fmap (\p -> readable p && searchable p) $ getPermissions file
traverseTree :: FilePath -> Producer FilePath IO()
traverseTree path = (`evalStateT` empty) $ loop $ do
-- All code past this point uses the following monad transformer stack:
-- MaybeT (StateT (Seq FilePath) (Producer FilePath IO))()
let liftState = lift
liftPipe = lift . lift
liftIO = lift . lift . lift
liftState $ modify (|> path)
forever $ do
x <- liftState $ gets viewl
case x of
EmptyL -> quit
file :< s -> do
liftState $ put s
liftPipe $ yield file
p <- liftIO $ doesDirectoryExist file
when p $ do
names <- liftIO $ getUsefulContents file
-- allowedNames <- filterM permissible names
let namesfull = map (path </>) names
liftState $ forM_ namesfull $ \name -> modify (|> name)
यह चौड़ाई-पहले फ़ाइल नाम है कि पेड़ ट्रेवर्सल के साथ समवर्ती सेवन किया जा सकता का एक जनरेटर पैदा करता है।
printer :: (Show a) => Consumer a IO r
printer = forever $ do
a <- await
lift $ print a
>>> runPipe $ printer <+< traverseTree path
<Prints file names as it traverses the tree>
तुम भी चुन सकते हैं सभी मूल्यों मांग नहीं करने के लिए:: आप का उपयोग कर मूल्यों का उपभोग इससे भी महत्वपूर्ण बात
-- Demand only 'n' elements
take' :: (Monad m) => Int -> Pipe a a m()
take' n = replicateM_ n $ do
a <- await
yield a
>> runPipe $ printer <+< take' 3 <+< traverseTree path
<Prints only three files>
, कि पिछले उदाहरण केवल पेड़ पार किए जाने के रूप में ज्यादा के रूप में आवश्यक तीन उत्पन्न करने के लिए फाइलें और फिर यह रुक जाएगी। यह पूरे पेड़ को बर्बाद कर देता है जब आप चाहते थे कि 3 परिणाम थे!
pipes
लाइब्रेरी चाल के बारे में और जानने के लिए, pipes tutorial पर Control.Pipes.Tutorial
पर परामर्श लें।
लूप चाल के बारे में और जानने के लिए, यह blog post पढ़ें।
मुझे चौड़ाई पहले ट्रैवर्सल के लिए कतार चाल के लिए एक अच्छा लिंक नहीं मिला, लेकिन मुझे पता है कि यह कहीं कहीं बाहर है। अगर कोई और इसके लिए एक अच्छा लिंक जानता है, तो बस इसे जोड़ने के लिए मेरा जवाब संपादित करें।
स्रोत
2012-09-26 22:16:40
आपके कोड के लिए धन्यवाद। पाइप को समझने में यह एक बड़ी मदद है। मैं कंडिट्स के बारे में पढ़ रहा था और इसका इस्तेमाल करने की योजना बना रहा था, लेकिन उम्मीद थी कि मुझे पहले पेड़ के ट्रैवर्सल के लिए एक साधारण आलसी समाधान होना चाहिए। मैंने कोशिश की और यह काम करता है, लेकिन यह पेड़ की मरम्मत नहीं करता है और मुझे नहीं पता कि यह आपके कोड में कहां जाएगा। गुम कोड फ़िल्टर कर रहा है "।" और ".." dirs की सूची से getUsefulContents पथ = नाम <है - गहरी निरीक्षण पर getDirectoryContents पथ वापसी (फिल्टर ('notElem' ["। "" .. "]) नाम) – user855443
मैं देख (छुपा) लिफ्टस्टेट के साथ अंतिम पंक्ति में रिकर्सन, जहां नए फ़ाइल नाम "todo" सूची में जोड़े जाते हैं। मुझे यह नहीं देखा, क्योंकि कोड अतिरिक्त फ़ाइलों के लिए पूर्ण फ़ाइलपथ नहीं बनाता है। पथ का मान मूल प्रारंभ मान है और प्रत्येक बार वर्तमान फ़ाइल नाम पर सेट नहीं है -> फ़ाइल के साथ पथ को प्रतिस्थापित करें, फिर यह काम करता है। पूरी तरह से काम करने के लिए, मुझे निर्देशिका पर अनुमतियों की जांच करनी है, जो मैं getInfo :: FilePath -> IO Info से करता हूं जो मैंने असली दुनिया हैकेल अध्याय 9 से लिया है। – user855443
यह लिंक का सामना करते समय कठिनाइयों में चलता है और मैं लिंक को फ़िल्टर करने के लिए भी एक टेस्ट जोड़ना होगा। यह मेरे सभी 4 कोर काम करता है और उपयोग करता है! अभी भी एक स्मृति रिसाव है, क्योंकि उपयोग स्मृति से बाहर होने तक बहुत धीरे-धीरे बढ़ता है। क्या आप देख सकते हैं? आपकी सहायता की बहुत सराहना की गई है, यह वही था जो मुझे एक पेड़ की यात्रा करते समय पाइप का उपयोग करने का एक अच्छा व्यावहारिक उदाहरण था! – user855443