2015-08-22 2 views
10

मैंक्या मैं हास्केल में डेटा कंस्ट्रक्टर वाइल्डकार्ड से मेल खाता हूं?

data Foo = X (String, Int) | A String | B String | C String | D String -- ... 

है और

f (X (s, _)) =s 
f (A s) = s 
f (B s) = s 
f (C s) = s 
f (D s) = s 
-- ... 

परिभाषित किया है लेकिन

f (X (s, _)) =s 
f (_ s) = s 

की तरह कुछ लिखने के लिए सक्षम होने के लिए पसंद करेंगे लेकिन इस (मैं ऐसा करने का कोई तरीका नहीं हो रहा है _ से जुड़े "पार्स त्रुटि" प्राप्त करें)।

क्या हास्केल में डेटा कंस्ट्रक्टर वाइल्डकार्ड से मिलान करने का कोई तरीका है?

+0

हालांकि भाषा में ऐसी कोई चीज़ उपलब्ध नहीं है (सिवाय इसके कि आप [जेनेरिक] (https://wiki.haskell.org/Generics) या [टेम्पलेट हास्केल] (https: //wiki.haskell) का उपयोग करने पर विचार कर सकते हैं। संगठन/टेम्पलेट_हास्केल) इस तरह के कोड उत्पन्न करने के लिए। क्या यह आपके उपयोग के मामले के लिए उचित होगा? –

उत्तर

15

नहीं। लेकिन आप इसे लिख सकते हैं:

data Foo 
    = X { name :: String, age :: Int } 
    | A { name :: String } 
    | B { name :: String } 
    | C { name :: String } 
    | D { name :: String } 

और उसके बाद name :: Foo -> String है। आप भी इस पर विचार कर सकते: @ DanielWagner के जवाब देने के लिए

data Tag = A | B | C | D 
data Foo = X String Int | Tagged Tag String 

f (X s _) = s 
f (Tagged _ s) = s 
+0

मुझे लगता है कि दृष्टिकोण की पसंद (जिसकी मैं कम से कम आपका दूसरा बनाम उपयोग कर रहा था) इस पर निर्भर करता है कि कितने "टैग किए गए" हैं प्रैक्टिस में, मेरे पास कुछ हैं (और कुछ अलग-अलग रूपों के साथ अधिक रचनाकार हैं) और मुझे लगता है कि मेरे पास दृष्टिकोण सबसे साफ हो सकता है। क्या कोई * वैचारिक * कारण है जो इन तीनों तरीकों में से किसी एक को चुनने का कारण है? – orome

+0

@ raxacoricofallapatorius जो कोई समझ में आता है उस पर निर्भर करता है कि आप किस प्रकार का मतलब चाहते हैं - जैसे कि आप कुछ मामलों में '2 * 1 + 2 * 2 + 2 * 3' लिख सकते हैं और' 2 * (1 + 2 + 3) ' दूसरों के विभिन्न कारणों पर जोर देने के लिए संख्या '12' में रुचि रखने के लिए। –

+1

@raxacoricofallapatorius, यदि तार प्रत्येक मामले में एक ही चीज़ का प्रतिनिधित्व करते हैं, तो टैग दृष्टिकोण समझ में आता है। यदि तार असंबद्ध हैं, तो आप शायद तीन रचनाकार चाहते हैं। तथ्य यह है कि आप तारों को एक ही चीज़ करना चाहते हैं, भले ही सुझाव दिया जाए, लेकिन इसका मतलब यह नहीं है कि टैग किए गए दृष्टिकोण को समझ में आता है। – dfeuer

3

इसके अलावा, एक विकल्प का उपयोग करने के Scrap your boilerplate (उर्फ "SYB") है। यह आपको किसी दिए गए प्रकार के पहले उपमहाद्वीप को खोजने की अनुमति देता है। तो तुम

{-# LANGUAGE DeriveDataTypeable #-} 

import Control.Monad 
import Data.Data 
import Data.Generics.Schemes 
import Data.Typeable 

data Foo = X (String, Int) | A String | B String | C String | D String 
    deriving (Show, Eq, Ord, Data, Typeable) 

fooString :: Foo -> Maybe String 
fooString = msum . gmapQ cast 

निर्धारित कर सकते हैं और fooString अपने निर्माताओं की पहली String तर्क वापस आ जाएगी। फंक्शन castString एस और gmapQ फ़िल्टर करता है सभी तत्काल उपखंडों के लिए फ़िल्टर किए गए मान प्राप्त करता है।

हालांकि, इस X से String वापस नहीं होगा, क्योंकि X तत्काल कोई String subterm है, यह प्रकार (String, Int) का केवल एक ही subterm है। आदेश अवधि पदानुक्रम में कहीं भी पहले String पाने के लिए, आप इस्तेमाल कर सकते हैं everywhere:

fooString' :: Foo -> Maybe String 
fooString' = everything mplus cast 

ध्यान दें कि इस दृष्टिकोण से थोड़ा कमजोर है: यह बस सभी String यह पाता है, हमेशा आप क्या चाहते हैं नहीं हो सकता है जिसमें शामिल , विशेष रूप से, यदि आप बाद में अपना डेटा प्रकार (या कुछ डेटा प्रकार जो संदर्भित करते हैं) का विस्तार करते हैं।

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