2011-12-14 16 views
24

हास्केल में ऐसा करने का सही तरीका क्या है?फ़ाइल को निकालें यदि यह मौजूद है

if exists "foo.txt" then delete "foo.txt" 
doSomethingElse 

अब तक मेरे पास है:

import System.Directory 
main = do 
     filename <- getFileNameSomehow 
     fileExists <- doesFileExist filename 
     if fileExists 
      then removeFile filename 
      ??? 
     doSomethingElse 
+4

'doesFileExist' फ़ंक्शन वास्तव में दौड़ की स्थितियों का निमंत्रण है। यह अस्तित्व में नहीं होना चाहिए। – augustss

+7

@augustss: हम इसके बारे में सिर्फ 'didFileExistLastTimeIChecked' का नाम बदलते हैं? –

+4

मैं सुझाव देता हूं 'didFileNotNeverExist'। – ehird

उत्तर

44

आप फ़ाइल को हटाने और बस अगर यह मौजूद नहीं है उबरने बंद बेहतर होगा:

import Prelude hiding (catch) 
import System.Directory 
import Control.Exception 
import System.IO.Error hiding (catch) 

removeIfExists :: FilePath -> IO() 
removeIfExists fileName = removeFile fileName `catch` handleExists 
    where handleExists e 
      | isDoesNotExistError e = return() 
      | otherwise = throwIO e 

यह किसी की रेस स्थिति के बीच फ़ाइल को हटाने से बचा जाता है अपने कोड जांच रहा है कि यह मौजूद है और इसे हटा देता है। यह आपके मामले में कोई फर्क नहीं पड़ता है, लेकिन यह वैसे भी अच्छा अभ्यास है।

import Prelude hiding (catch) लाइन पर ध्यान दें - ऐसा इसलिए है क्योंकि प्रीलूड में अपवाद हैंडलिंग से पुराने कार्य शामिल हैं जिन्हें अब नियंत्रण.एक्सप्शन के पक्ष में बहिष्कृत किया गया है, जिसमें catch नामक फ़ंक्शन भी है; आयात लाइन Control.Exception के पक्ष में प्रीलूड के catch को आसानी से छुपाती है।

हालांकि, कि अभी भी अपने अधिक मौलिक अंतर्निहित सवाल छोड़: कैसे आप IO में सशर्त, लिख सकता हूँ?

वैसे, इस मामले में, यह पर्याप्त होगा बस (Control.Monad.when का उपयोग कर)

when fileExists $ removeFile filename 

क्या करना है। लेकिन यह यहां सहायक है, क्योंकि यह आमतौर पर प्रकारों को देखने के लिए हैस्केल में है।

एक सशर्त दोनों शाखाओं में एक ही प्रकार होना आवश्यक है। तो भरने के लिए

if fileExists 
    then removeFile filename 
    else ??? 

हम removeFile filename के प्रकार पर गौर करना चाहिए; जो भी ??? है, यह एक ही प्रकार का होना चाहिए।

System.Directory.removeFile प्रकार FilePath -> IO() है, इसलिए removeFile filename प्रकार IO() है। तो हम () के परिणामस्वरूप एक आईओ कार्रवाई चाहते हैं जो कुछ भी नहीं करता है।

खैर, return के प्रयोजन के लिए एक कार्रवाई नहीं असर पड़ता है कि निर्माण करने के लिए है, और सिर्फ एक निरंतर मान देता है, और return() इस के लिए सही प्रकार का है: IO() (या अधिक सामान्यतः, (Monad m) => m())। तो ???return() है (जो आप देख सकते हैं जब removeFile विफल रहता है मैं ऊपर मेरी बेहतर स्निपेट में इस्तेमाल किया, कुछ भी नहीं करना है क्योंकि फ़ाइल मौजूद नहीं है)।

(वैसे, तुम अब return() की मदद से when लागू करने में सक्षम होना चाहिए, यह वास्तव में आसान है :))

चिंता मत करो अगर आप इसे कठिन चीजों में से हास्केल मार्ग में प्राप्त करने के लिए लगता है पहले - यह समय पर स्वाभाविक रूप से आ जाएगा, और जब ऐसा होता है, तो यह बहुत ही फायदेमंद है। :)

+4

यहाँ Control.Exception के दस्तावेज़ के लिए एक लिंक है: http://hackage.haskell.org/packages/archive/base/latest/doc/html/Control-Exception.html - मैं इसे क्योंकि मैं डॉन पोस्ट में नहीं डाल सकता है पर्याप्त प्रतिष्ठा नहीं है:/ – ehird

+2

धन्यवाद, यह वास्तव में सहायक था! – yogsototh

+1

कोई समस्या नहीं है - जहाँ तक पठन सामग्री चला जाता है, वहाँ उत्कृष्ट [आप जानें हास्केल] (http://learnyouahaskell.com/) और [असली दुनिया हास्केल] (http://book.realworldhaskell.org/), लेकिन मुझे कल्पना है कि आप इनके बारे में पहले से ही जानते हैं। मैं [Hoogle] (http://www.haskell.org/hoogle/) की हास्केल प्रोग्रामिंग के लिए अमूल्य के रूप में टाइप करने की क्षमता की सिफारिश कर सकता हूं। – ehird

10

(नोट: ehird का जवाब एक दौड़ हालत के बारे में एक बहुत अच्छा बिंदु बनाता है यह ध्यान में रखा जाना चाहिए जब मेरा उत्तर है, जो ध्यान नहीं देता पढ़ने। मुद्दा। भी क्या टिप्पणी है कि जरूरी छद्म कोड प्रश्न में प्रस्तुत भी एक ही समस्या से ग्रस्त है।)

फ़ाइल नाम क्या परिभाषित करता है? क्या यह कार्यक्रम में दिया गया है, या उपयोगकर्ता द्वारा आपूर्ति की जाती है? आपके अनिवार्य छद्म कोड में, यह प्रोग्राम में निरंतर स्ट्रिंग है। मैं मानता हूं कि आप चाहते हैं कि उपयोगकर्ता इसे प्रोग्राम के लिए पहली कमांड लाइन तर्क के रूप में पास करके इसे आपूर्ति करे।

import Control.Monad  
import System.Directory 
import System.Environment 

doSomethingElse :: IO() 

main = do 
    args <- getArgs 
    fileExists <- doesFileExist (head args) 
    when fileExists (removeFile (head args)) 
    doSomethingElse 

(जैसा कि आप देख सकते हैं, मैं doSomethingElse के प्रकार के हस्ताक्षर भ्रम से बचने के लिए जोड़ा):

तो मैं कुछ इस तरह का सुझाव दें।

मैं getArgs समारोह के लिए System.Environment आयात करते हैं। यदि प्रश्न में फ़ाइल को एक स्थिर स्ट्रिंग (जैसे कि आपके अनिवार्य छद्म कोड में) द्वारा दिया जाता है, तो बस सभी तर्क सामग्री को हटा दें और जहां भी मेरे पास head args है, निरंतर स्ट्रिंग भरें।

Control.Monadwhen समारोह पाने के लिए आयात किया जाता है। ध्यान दें कि यह उपयोगी समारोह शब्द नहीं (जैसे if), लेकिन एक साधारण समारोह है। के अपने प्रकार पर नजर डालते हैं:

when :: Monad m => Bool -> m() -> m() 

अपने मामले m में, IO है ताकि आप एक समारोह है कि एक Bool और एक आईओ कार्रवाई करती है और कार्रवाई केवल तभी BoolTrue है प्रदर्शन के रूप में when के बारे में सोच सकते हैं। बेशक आप if एस के साथ अपनी समस्या का समाधान कर सकते हैं, लेकिन आपके मामले में when बहुत स्पष्ट पढ़ता है। कम से कम मुझे तो यही लगता है।

परिशिष्ट: आप, जैसा कि मैंने पहली बार में किया था, लग रहा है कि when कुछ जादुई और मुश्किल मशीनरी है मिलता है, यह समारोह अपने आप को परिभाषित करने की कोशिश करने के लिए बहुत शिक्षाप्रद है। मैं तुमसे वादा करता हूँ, यह मृत सरल है ...

+4

यह सोचने के लिए भी निर्देशक है * क्यों * यह 'कब' परिभाषित करना आसान है, और इसके अन्य प्रभाव क्या हैं। इंपेरेटिव कोड ब्लॉक हास्केल में प्रथम श्रेणी की इकाइयां हैं, जिससे कुछ भाषाएं मिल सकती हैं। –

संबंधित मुद्दे