आपकी दूसरी, विशिष्ट, समस्या आपके कार्यों के प्रकारों के साथ है। हालांकि, आपका पहला मुद्दा (वास्तव में एक प्रकार की चीज़ नहीं) getFileNameAndSize
में कथन है। जबकि do
मोनैड के साथ प्रयोग किया जाता है, यह एक monadic panacea नहीं है; यह वास्तव में some simple translation rules के रूप में लागू किया गया है। क्लिफ नोट्स संस्करण (जो बिल्कुल सही, त्रुटि हैंडलिंग से जुड़े कुछ विवरण के लिए धन्यवाद, नहीं है, लेकिन पर्याप्त करीब है) है:
do a
≡ a
do a ; b ; c ...
≡ a >> do b ; c ...
do x <- a ; b ; c ...
≡ a >>= \x -> do b ; c ...
दूसरे शब्दों में, getFileNameAndSize
के बिना संस्करण के बराबर हैब्लॉक, और इसलिए आप do
से छुटकारा पा सकते हैं। यह हम इस के लिए प्रकार पा सकते हैं
getFileNameAndSize fname = (fname, withFile fname ReadMode hFileSize)
के साथ छोड़ देता है: के बाद से fname
withFile
को पहला तर्क है, यह टाइप FilePath
है; और hFileSize
IO Integer
देता है, तो यह withFile ...
का प्रकार है। इस प्रकार, हमारे पास getFileNameAndSize :: FilePath -> (FilePath, IO Integer)
है। यह हो सकता है कि आप जो चाहते हैं हो या न हो; आप इसके बजाय FilePath -> IO (FilePath,Integer)
चाहते हैं।इसे बदलने के लिए, आपको
getFileNameAndSize_do fname = do size <- withFile fname ReadMode hFileSize
return (fname, size)
getFileNameAndSize_fmap fname = fmap ((,) fname) $
withFile fname ReadMode hFileSize
-- With `import Control.Applicative ((<$>))`, which is a synonym for fmap.
getFileNameAndSize_fmap2 fname = ((,) fname)
<$> withFile fname ReadMode hFileSize
-- With {-# LANGUAGE TupleSections #-} at the top of the file
getFileNameAndSize_ts fname = (fname,) <$> withFile fname ReadMode hFileSize
अगला के किसी भी लिख सकते हैं, के रूप में KennyTM ने कहा, आप fileNames <- getDirectoryContents
है; चूंकि getDirectoryContents
में FilePath -> IO FilePath
टाइप है, तो आपको इसे एक तर्क देना होगा। (उदा।getFilesWithSizes dir = do fileNames <- getDirectoryContents dir ...
)। यह शायद सिर्फ एक साधारण निरीक्षण है।
mext, हम अपने त्रुटि के दिल के लिए आते हैं: files <- (mapM getFileNameAndSize fileNames)
। मुझे यकीन नहीं है कि यह आपको सटीक त्रुटि क्यों देता है, लेकिन मैं आपको बता सकता हूं कि क्या गलत है। याद रखें कि हम getFileNameAndSize
के बारे में क्या जानते हैं। आपके कोड में, यह (FilePath, IO Integer)
देता है। हालांकि, mapM
टाइप Monad m => (a -> m b) -> [a] -> m [b]
है, और इसलिए mapM getFileNameAndSize
खराब टाइप है। आप getFileNameAndSize :: FilePath -> IO (FilePath,Integer)
चाहते हैं, जैसा कि मैंने उपरोक्त कार्यान्वित किया है।
अंत में, हम अपने अंतिम पंक्ति को ठीक करने की जरूरत है। सबसे पहले, हालांकि आप इसे हमें नहीं देते हैं, cmpFilesBySize
संभावित रूप से दूसरे तत्व की तुलना में (FilePath, Integer) -> (FilePath, Integer) -> Ordering
प्रकार का एक कार्य है। यह वास्तव में सरल है, हालांकि: Data.Ord.comparing :: Ord a => (b -> a) -> b -> b -> Ordering
का उपयोग करके, आप यह comparing snd
लिख सकते हैं, जिसमें Ord b => (a, b) -> (a, b) -> Ordering
है। दूसरा, आपको एक सादा सूची के बजाय आईओ मोनैड में अपना परिणाम लपेटना होगा; फ़ंक्शन return :: Monad m => a -> m a
चाल करेगा।
इस प्रकार, यह सब एक साथ डाल, तो आप
import System.IO (FilePath, withFile, IOMode(ReadMode), hFileSize)
import System.Directory (getDirectoryContents)
import Control.Applicative ((<$>))
import Data.List (sortBy)
import Data.Ord (comparing)
getFileNameAndSize :: FilePath -> IO (FilePath, Integer)
getFileNameAndSize fname = ((,) fname) <$> withFile fname ReadMode hFileSize
getFilesWithSizes :: FilePath -> IO [(FilePath,Integer)]
getFilesWithSizes dir = do fileNames <- getDirectoryContents dir
files <- mapM getFileNameAndSize fileNames
return $ sortBy (comparing snd) files
मिलेगा यह सब अच्छी तरह से और अच्छा है, और ठीक से काम करेगा। हालांकि, मैं इसे थोड़ा अलग लिख सकता हूं। बंद
{-# LANGUAGE TupleSections #-}
import System.IO (FilePath, withFile, IOMode(ReadMode), hFileSize)
import System.Directory (getDirectoryContents)
import Control.Applicative ((<$>))
import Control.Monad ((<=<))
import Data.List (sortBy)
import Data.Ord (comparing)
preservingF :: Functor f => (a -> f b) -> a -> f (a,b)
preservingF f x = (x,) <$> f x
-- Or liftM2 (<$>) (,), but I am not entirely sure why.
fileSize :: FilePath -> IO Integer
fileSize fname = withFile fname ReadMode hFileSize
getFilesWithSizes :: FilePath -> IO [(FilePath,Integer)]
getFilesWithSizes = return . sortBy (comparing snd)
<=< mapM (preservingF fileSize)
<=< getDirectoryContents
(<=<
.
की monadic बराबर, समारोह रचना ऑपरेटर है।) प्रथम:: मेरी संस्करण शायद इस प्रकार दिखाई देगा हाँ, मेरी संस्करण अब है। हालांकि, मैं शायद पहले से ही है preservingF
कहीं परिभाषित होता है, जिससे दो लंबाई में बराबर। * (मैं हो सकता है यहां तक कि इनलाइन fileSize
अगर यह कहीं और इस्तेमाल नहीं किया गया।) दूसरा, मैं इस संस्करण बेहतर पसंद है, क्योंकि यह एक साथ सरल शुद्ध कार्यों चेनिंग शामिल हम पहले से ही लिखे हैं। जबकि आपका संस्करण समान है, मेरा (मुझे लगता है) अधिक सुव्यवस्थित है और चीजों के इस पहलू को स्पष्ट बनाता है।
तो यह कैसे इन बातों की संरचना करने के अपने पहले प्रश्न का उत्तर का एक सा है। मैं व्यक्तिगत रूप से मेरे आईओ जो बाहर की दुनिया सीधे (जैसेmain
और जो कुछ भी एक फ़ाइल के साथ सूचना का आदान प्रदान) एक IO
पाने को स्पर्श करना संभव-केवल कार्यों के रूप में के रूप में कुछ कार्यों में नीचे लॉक करने के लिए करते हैं। बाकी सब कुछ एक सामान्य शुद्ध कार्य है (और यह केवल मोनैडिक है यदि यह preservingF
की तर्ज पर सामान्य कारणों से मोनैडिक है)। मैं तो बातें की व्यवस्था इतनी है कि main
, आदि, बस रचनाओं और शुद्ध कार्यों की श्रृंखला हैं: main
IO
-land से कुछ मान हो जाता है; तो यह तारीख को गुना करने, धुंधला करने और विचलित करने के लिए शुद्ध कार्यों को बुलाता है; तो यह IO
मान प्राप्त करता है; तो यह अधिक संचालित करता है; इत्यादि। विचार दो डोमेन को यथासंभव अलग करना है, ताकि अधिक रचनात्मक गैर -IO
कोड हमेशा नि: शुल्क होता है, और ब्लैक-बॉक्स IO
केवल वही किया जाता है जहां आवश्यक हो।
ऑपरेटर्स <=<
की तरह वास्तव में, इस शैली में लेखन कोड के साथ मदद के रूप में वे आप कार्यों जो (जैसे IO
-world के रूप में) monadic मूल्यों के साथ बातचीत आप सामान्य कार्यों पर कार्य करते हैं बस के रूप में पर काम करते हैं।आपको Control.Applicative'sfunction <$> liftedArg1 <*> liftedArg2 <*> ...
नोटेशन भी देखना चाहिए, जो आपको किसी भी प्रकार के मोनैडिक (वास्तव में Applicative
) तर्कों के लिए सामान्य कार्यों को लागू करने देता है। यह नकली <-
एस से छुटकारा पाने के लिए वास्तव में अच्छा है और केवल मोनैडिक कोड पर शुद्ध कार्यों को चेन करना।
*: मुझे लगता है कि preservingF
, या कम से कम इसके भाई preserving :: (a -> b) -> a -> (a,b)
, कहीं पैकेज में होना चाहिए, लेकिन मैं या तो खोजने में असमर्थ हूं।
धन्यवाद, महान जवाब है, मैं अभी भी समझ में बहुत कम मैं लगता है क्योंकि मैं इसके बारे में 40% को समझते हैं, लेकिन यह समस्या हल हो;) – Drakosha
खुशी है कि मैं मदद कर सकता है। क्या विशेष रूप से कुछ भी आपको नहीं मिलता है? अंत में बहुत सारी चीजें एक और चीज है जो मुझे लगता है कि आप शायद कुछ सीखने/सीखना चाहें, जैसा कि मुझे लगता है कि आपको पहले ही पता होना चाहिए। –