2012-02-22 10 views
8
में नीचे मूल्य का पता लगाने

मैं एक Haskell समारोह जो इतनी तरह (init xs, last xs) में एक सूची xs विभाजन लिखा है:हास्केल

split xs = split' [] xs 
    where 
     split' acc (x:[]) = (reverse acc, x) 
     split' acc (x:xs) = split' (x:acc) xs 

के बाद से एक खाली सूची इस तरह से विभाजित नहीं किया जा सकता है, वहाँ के लिए कोई मुकाबला नहीं है खाली सूची हालांकि, मैं बस error ... फ़ंक्शन नहीं चाहता था।

split [] = ([], undefined) 

आलसी मूल्यांकन के लिए धन्यवाद मैं इस तरह एक सुरक्षित init जो केवल खाली सूची के लिए खाली सूची रिटर्न परिभाषित कर सकते हैं:

init' = fst . split 

वहाँ किसी तरह मैं कैसे पता लगा सकता है इस प्रकार मैं निम्नलिखित परिभाषित अपरिभाषित मैं इसे उपयोग करने की कोशिश की, ऐसी है कि

last' xs 
    | isUndefined (snd xs) = ... 
    | otherwise   = ... 

मैं के बारे में Maybe और Either, और कहा कि पता चले कि क्या जो मैं चाहता हूं उसे व्यक्त करने के लिए वे बेहतर विकल्प हैं। हालांकि मुझे आश्चर्य हुआ कि क्या अपरिभाषित वास्तविक मूल्य का पता लगाने का कोई तरीका है, यानी अपवादों को पकड़ने जैसी त्रुटियों को पकड़ने के मामले में।

+3

सरल उत्तर नहीं है। अपरिभाषित पता लगाना संभव नहीं है। (एक और जटिल जवाब यह है कि आप आईओ मामाद में अपवादों को पकड़ सकते हैं, लेकिन यह नहीं है कि आप यहां क्या करना चाहते हैं।) – augustss

उत्तर

10

क्योंकि नीचे subsumes गैर समाप्ति, समारोह isUndefined हॉल्टिंग समस्या को हल करने के लिए है और इस प्रकार हैं अस्तित्व में नहीं हो सकता

लेकिन ध्यान दें कि यहां तक ​​कि यदि यह अस्तित्व में है, तो भी आप यह नहीं बता सकते कि आपके ट्यूपल के दूसरे तत्व में अपरिभाषित मूल्य आपके split फ़ंक्शन के माध्यम से रखा गया था या यदि सूची का अंतिम तत्व पहले से ही अपरिभाषित था।

+1

यदि कोई फ़ंक्शन मौजूद है जो हल करने की समस्या को हल करता है, तो हम गलत दिखा सकते हैं, और इसलिए, हम सब कुछ दिखा सकते हैं, जिसमें "हम बता सकते हैं कि आपके स्प्लिट फ़ंक्शन के माध्यम से आपके ट्यूपल के दूसरे तत्व में अपरिभाषित मान रखा गया था या नहीं सूची का अंतिम तत्व पहले से ही अपरिभाषित था। " –

8

जब तक यह मूल्यांकन किया जाता है error समारोह कुछ नहीं करता है, तो आप की तरह कुछ कर सकते हैं:

split [] = ([], error "split: empty list") 

last' = snd . split 
+0

मेरी राय में सबसे अच्छा जवाब, क्योंकि यह अगले प्रश्न का उत्तर देता है, वैसे भी: " मैं 'अन्यथा 'खंड में क्या डालूं?"। –

+0

मुझे यह पता है, जैसा कि मैंने कहा था "आलसी मूल्यांकन के लिए धन्यवाद" - त्रुटि डालने की तरह वहां अपरिभाषित है। मैं इस बात को पहचानना चाहता था, लेकिन जैसा कि मैंने सीखा है कि यह संभव नहीं है क्योंकि नीचे के अर्थशास्त्र इसे मना कर देते हैं। एक सूचनात्मक संदेश के साथ 'त्रुटि' का उपयोग करने के लिए – scravy

+0

+1। ओपी की पसंद "मैं 'त्रुटि नहीं करना चाहता था ...'" और 'अपरिभाषित' का उपयोग करते हुए ज्यादातर डिबगिंग करते समय निराशा होती है: "हां, मैंने 'अपरिभाषित' मारा है, लेकिन * * अपरिभाषित' का उपयोग *?"। यह विशेष रूप से खराब है (जीएचसी) हास्केल, क्योंकि आलस्य और आक्रामक अनुकूलन एक संकलित प्रोग्राम को एक अप्रत्याशित क्रम में निष्पादित कर सकता है। स्टैक निशान हाल ही में जीएचसी में जोड़े गए हैं, लेकिन बाइनरी वास्तव में निष्पादित करने के तरीके के वास्तविक रिकॉर्ड के बजाए वे अभी भी एक भ्रम का विकल्प चुन रहे हैं। बस हमें बताएं कि पहले स्थान पर क्या गलत हुआ! – Warbo

11

undefinederror का उपयोग करने से बेहतर नहीं है। वास्तव में, प्रस्तावना में undefineddefined

रूप
undefined = error "Prelude.undefined" 


अब, एक समारोह है कि एक error में परिणाम नहीं कर सकते हैं एक "कुल समारोह" कहा जाता है, अर्थात यह सब इनपुट मानों के लिए मान्य है।

split समारोह आप वर्तमान में क्रियान्वित किया है के बाद से प्रकार हस्ताक्षर वादा करता है कि परिणाम हमेशा एक सूची और एक तत्व है, जिसके लिए प्रदान करने के लिए स्पष्ट रूप से असंभव है शामिल है, हस्ताक्षर

split :: [a] -> ([a], a) 

यह एक समस्या है जेनेरिक प्रकार की खाली सूचियां।

हास्केल में इसका कैननिक तरीका यह हल करने के लिए प्रकार हस्ताक्षर को बदलना है कि कभी-कभी हमारे पास दूसरे आइटम के लिए वैध मान नहीं है।

split :: [a] -> ([a], Maybe a) 

अब आप इस मामले में जहां आप एक खाली सूची

split [] = ([], Nothing) 
split xs = split' [] xs 
    where 
     split' acc (x:[]) = (reverse acc, Just x) 
     split' acc (x:xs) = split' (x:acc) xs 

अब आप पैटर्न मिलान

let (init', last') = split xs 
in case last' of 
    Nothing -> ... -- do something if we don't have a value 
    Just x -> ... -- do something with value x 
+3

थोड़ा विडंबना जो परिभाषित किया गया है परिभाषित किया गया है;) –

+1

@ डैनबर्टन ठीक है, अगर यह आपका हास्य है, तो ध्यान दें कि 'अनिर्धारित' को परिभाषित करना भी संभव है: 'अपरिभाषित = अपरिभाषित'। यह अलग व्यवहार करता है (यह परिभाषा मजबूर होने पर समाप्त नहीं होती है), लेकिन अर्थात्, यह वही मान (नीचे) है। –

4

से से लापता मूल्य मामले का पता लगा सकते प्राप्त करने के लिए एक उचित कार्यान्वयन लिख सकते हैं Haskell 2010 Language Report > Introduction # Values and Types

हास्केल में त्रुटियां अर्थात् ⊥ ("नीचे") के बराबर होती हैं। तकनीकी रूप से, वे nontermination से अलग नहीं हैं, इसलिए भाषा में त्रुटियों का पता लगाने या अभिनय के लिए कोई तंत्र शामिल नहीं है।

स्पष्ट है कि, undefined अपने कार्यक्रम में ⊥ डालने के लिए एक तरह से करने का इरादा है, और दिया जाता है कि (शांग नोट) undefinederror के संदर्भ में परिभाषित किया गया है, वहाँ है, इसलिए "का पता लगाने के लिए कोई तंत्र या undefined पर अभिनय "।

+1

हालांकि यह हास्केल 2010 के दृष्टिकोण से सही है, यह ध्यान देने योग्य है कि जीएचसी हास्केल में, कुछ त्रुटि, जिनमें 'त्रुटि' शामिल है, अपवाद के रूप में लागू किए जाते हैं, जिन्हें 'आईओ' मोनैड में पकड़ा जा सकता है। हालांकि, ऐसा करने से आमतौर पर खराब डिजाइन का संकेत मिलता है, क्योंकि शुद्ध कोड में त्रुटियों को संभालने के बेहतर तरीके हैं। (यहां तक ​​कि एक 'nonTermination' अपवाद भी है जिसे रनटाइम गैर-समाप्ति का पता लगा सकता है, हालांकि यह रोकथाम की समस्या के कारण निश्चित रूप से विश्वसनीय नहीं है)। – hammar

1

हालांकि, यदि आप जीएचसी का उपयोग कर रहे हैं, तो अर्थात् इनगो का जवाब सही है, फिर भी कुछ "असुरक्षित" फ़ंक्शंस का उपयोग करने का एक तरीका है, हालांकि यह बिल्कुल सही नहीं है कि आप इसे टाइप IO की गणना करते हैं जिसमें एक है एक अपवाद यह सच हो जाएगा, काम करता है। हालांकि यह धोखाधड़ी का थोड़ा सा है :)।

import Control.Exception 
import System.IO.Unsafe 
import Unsafe.Coerce 

isUndefined :: a -> Bool 
isUndefined x = unsafePerformIO $ catch ((unsafeCoerce x :: IO()) >> return False) (const $ return True :: SomeException -> IO Bool) 

मैं जानता हूँ कि यह भयानक है, लेकिन कोई भी कम यह काम करता है। हालांकि यह गैर समाप्ति का पता नहीं लगाएगा;)

+0

अभ्यास में काफी 100% सटीकता के लिए "(\ e -> वापसी $ show e ==" prelude.undefined ")" द्वारा "रिटर्न फाल्स" को प्रतिस्थापित करके इसे बेहतर किया जा सकता है (जब तक कि कोई अपवाद नहीं बनाता है जो कार्यान्वयन करता है शो रिटर्न "Prelude.undefined", लेकिन वह मूर्खतापूर्ण होगा ...) –