2012-02-24 6 views
5

यह this one पर एक अनुवर्ती प्रश्न है। मुझे लगता है कि मैंने थोड़ा सा गलत समझा है कि हास्केल में क्या करना है, इसलिए उम्मीद है कि प्रश्न का बेहतर फॉर्मूलेशन:पैरामीटर के प्रकारों के बिल्कुल दो भिन्नताओं के साथ एक सामान्य कार्य लिखें

मैं एक ऐसा कार्य करना चाहता हूं जिसे बिल्कुल दो तर्कों के साथ बुलाया जा सके। ये तर्क विभिन्न प्रकार के होंगे। उदाहरण के लिए, एक स्ट्रिंग है, और दूसरा एक पूर्णांक है। मेरे लिए,

combine "100" 500 -- results in 100500 
combine 100 "500" -- results in 100500 
combine 100 500 -- raises an exception 
combine "100" "500" -- raises an exception 

यह एक ठोस कार्यान्वयन लिखने के लिए एक समस्या नहीं है, यह एक समस्या है, तथापि, यह समारोह एक उचित हस्ताक्षर देने के लिए:

इस आवेदन पर विचार करें।

मुझे यह जानने में भी दिलचस्पी होगी कि एक ऐसा समाधान है जो अधिक सामान्य है (यानी ठोस प्रकार निर्दिष्ट करने की आवश्यकता नहीं है, लेकिन केवल अलग-अलग प्रकार के लिए निर्धारित करता है। इसलिए, उदाहरण के लिए, आप इस सुविधा का उपयोग, अन्य कार्यों के लिए इनपुट "ठीक" करने के लिए यह तर्क permuting द्वारा निर्धारित किया जा सकता है अगर

धन्यवाद

संपादित करें:।!

नीचे

मैं क्या उम्मीद कर रहा था की एक अनिश्चित प्रति है यह Erlang में करने के लिए ... अच्छा, मुझे उम्मीद है कि यह समझ में आता है, क्योंकि यह काफी समान होना चाहिए ...

combine([String], Int)-> 
    io:fwrite("~s~w~n", [[String], Int]); 

combine(Int, [String])-> 
    combine([String], Int). 
+3

चूंकि यह प्रकार में कोई समस्या है, तो आप "एक अपवाद बढ़ा" नहीं करना चाहते, तो आप एक संकलन समय त्रुटि चाहेंगे। अंतर pedantic लग सकता है, लेकिन यह महत्वपूर्ण है। हास्केल में, यदि संभव हो तो हम हमेशा संकलन-समय त्रुटियों को चाहते हैं।साथ ही, ऐसा लगता है कि आप हास्केल के बजाय पायथन में सोच रहे हैं: पी –

+3

मैं कहूंगा कि ऐसा करने का सही तरीका लिखना है: 'गठबंधन :: इंटीजर -> स्ट्रिंग -> स्ट्रिंग'। यह गारंटी देता है कि यह प्रत्येक प्रकार का बिल्कुल एक तर्क लेगा। यह आसान है, यह स्पष्ट है। इसमें कोई उन्नत सुविधाएं शामिल नहीं हैं। आपके द्वारा और अधिक क्या पूछा जा सकता है? – Carl

+0

मैं व्यक्तिगत रूप से केवल दो कार्य करने की अनुशंसा करता हूं: 'combineStrInt :: स्ट्रिंग -> Int -> Int' और 'combineIntStr :: Int -> स्ट्रिंग -> Int'। मैं * केवल एक फ़ंक्शन की अनुशंसा करता हूं, और उसके बाद आवश्यक होने पर तर्कों के क्रम को उल्टा करने के लिए 'फ्लिप' का उपयोग करके, लेकिन आपके उदाहरण के लिए, पैरामीटर को फ़्लिप करने से सही परिणाम नहीं मिलेंगे। अभ्यास में, आपको शायद 'फ्लिप' उपयोगी लगेगा। बदसूरत और निराशाजनक के लिए –

उत्तर

7

जोएर्ड मुझे इससे हराएं , लेकिन मैं अपना समाधान पसंद करता हूं इसलिए मैं इसे वैसे भी पोस्ट करूंगा।

{-# LANGUAGE MultiParamTypeClasses, TypeSynonymInstances, FlexibleInstances #-} 

module Foo where 

class Combinable a b where 
    combine :: a -> b -> Int 

instance Combinable Int String where 
    combine a b = read (show a ++ b) 

instance Combinable String Int where 
    combine a b = read (a ++ show b) 

इस के बाद से उपयोग करने के लिए एक एक संकलन समय त्रुटि के बजाय एक रनटाइम त्रुटि है की कोशिश कर रहा एक Combinable a a उदाहरण शामिल नहीं है,।

3

मैं लगभग सकारात्मक हूं कि आप जेनेरिक चीज़ का वर्णन नहीं कर सकते हैं। आपके द्वारा वर्णित समानता की अस्वीकृति व्यक्त करने के लिए हास्केल में कोई रास्ता नहीं है।

आप OverlappingInstances और बहु-पैरामीटर प्रकार कक्षाओं का उपयोग करके कुछ वास्तव में गंदे हैक करने में सक्षम हो सकते हैं, जिसके परिणामस्वरूप संकलन-समय त्रुटियों के बजाए रनटाइम त्रुटियां होंगी, लेकिन यह वास्तव में बदसूरत और निराशाजनक होगी।

+0

+1। –

+0

वास्तव में, आप बहु-पैरामीटर प्रकार कक्षाओं/फ़ंक्शन निर्भरताओं/आदि के माध्यम से हास्केल में प्रकार असमानता को लागू कर सकते हैं और संकलन समय त्रुटियां प्राप्त कर सकते हैं। "ओलेग पहले से ही यह किया था।" टाइप स्तर प्रोग्रामिंग की एक बड़ी मात्रा इस पर निर्भर करती है। जहां तक ​​मुझे पता है कि यह एकमात्र प्रकार की नकारात्मक बाधा है जिसे लागू किया जा सकता है। टाइप परिवारों के साथ मिलकर यह ओडब्ल्यूएस का एक अवांछित उल्लंघन भी है। –

1

आपको अपना खुद का डेटा प्रकार बनाना है क्योंकि आपके पास हैकेल में अपरिभाषित प्रकार नहीं हो सकते हैं।

data IntAndString = TypeA Int String | TypeB String Int 

combine IntAndString -> string 
combine TypeA(n s) = show n ++ s 
combine TypeB(s n) = s ++ show n 

कर सकते हैं eiter गठबंधन

combine TypeA(Int String) 

या

combine TypeB(String Int) 
+0

उपरोक्त क्योंकि मुझे समाधान पसंद है, लेकिन आपका क्या मतलब है कि हास्केल में सामान्य प्रकार नहीं हो सकते हैं? –

+1

वैसे यह मेरे द्वारा गलत था। प्रकार जीनरिक हो सकते हैं लेकिन कार्य सामान्य नहीं हो सकते हैं – nist

3

बदसूरत और निराशाजनक समाधान लुइस Wasserman उल्लेख कुछ इस तरह किया जाएगा के साथ कहा जा:

{-# LANGUAGE MultiParamTypeClasses, TypeSynonymInstances, FlexibleInstances #-} 

class Combine a b where 
    combine :: a -> b -> String 

instance Combine a a where 
    combine = error "Types are the same" 

instance (Show a, Show b) => Combine a b where 
    combine a b = show a ++ show b 
+0

आप _probably_ को जीएचसी को निगलने के लिए ओवरलैपिंग इंस्टेंस की आवश्यकता होगी। –

+2

@ लुइस वासरमैन आश्चर्यजनक रूप से आप नहीं करते हैं। जब तक आप इसे किसी ऐसी स्थिति में उपयोग न करें जो _might_ 'combine :: a -> a -> स्ट्रिंग' का उपयोग करें। जीएचसी की ओवरलैप जांच आलसी है, यह आवश्यक होने तक ट्रिगर नहीं करता है। –

+0

हमारे उत्तर अनिवार्य रूप से वही हैं; केवल अंतर वे उदाहरण हैं जिन्हें हमने परिभाषित करने के लिए चुना है। कई हास्केलर्स के पास बड़ी संख्या में उदाहरण घोषित करने के लिए एक उलझन है (यदि आप अधिक प्रकार जोड़ना शुरू करते हैं तो मेरे दृष्टिकोण से गिरावट का विस्फोट हो जाएगा), लेकिन कभी-कभी आईएमएचओ यह सबसे अच्छा तरीका है। –

1

ठोस कार्यान्वयन लिखने में कोई समस्या नहीं है, यह समस्या है, हालांकि, मेरे लिए यह कार्य उचित हस्ताक्षर देने के लिए है।

जब तक कार्यों में उच्च रैंक प्रकार नहीं होते हैं, तो आपको इसकी आवश्यकता नहीं होती है। हास्केल आपके लिए प्रकार का अनुमान लगाएगा।

उस ने कहा, मुझे लगता है कि आप जो चाहते हैं वह हैस्केल में ज्यादा समझ नहीं लेता है, जहां कोड और डेटा सख्ती से अलग हो जाते हैं और साथ ही रन टाइम और संकलन समय, लिस्प के विपरीत। combine के लिए उपयोग केस क्या होगा?

¹ बेशक, कार्य एक अर्थ में डेटा हैं, लेकिन वे केवल पूरी तरह से अपारदर्शी स्थिरांक हैं। आप रन टाइम पर फ़ंक्शन में हेरफेर नहीं कर सकते हैं।

+1

यह आसान है: यह नहीं है। हास्केल में एकाधिक प्रेषण जैसी कोई चीज़ नहीं है। – Ingo

6

यह मेरे लिए 100% स्पष्ट नहीं है क्यों आप इसे चाहते हैं। एक संभावना है कि मैं उन लोगों के साथ आया जो दूसरों का उल्लेख नहीं किया गया था कि आप बस ऑर्डर-अज्ञेयवादी कार्य आवेदन चाहते हैं। यह "रिकॉर्ड आवेदन" मुहावरे के साथ संभव है।

data Argument = Argument { name :: String, age :: Int } 
instance Default Argument where def = Argument def def 

combine Argument { name = n, age = a } = name ++ " is " ++ show age ++ " years old" 

फिर आप नामित तर्क के साथ यह कॉल कर सकते हैं: उदाहरण के लिए, आप कुछ इस तरह लिख सकते हैं

combine def { name = "Daniel", age = 3 } 
combine def { age = 3, name = "Daniel" } 

नाम भी सिर्फ एक बालक की जाँच है कि प्रकार के बराबर नहीं हैं की तुलना में बेहतर कर रहे हैं, क्योंकि आप अस्पष्टता के बिना एक ही प्रकार के साथ कई तर्क प्राप्त कर सकते हैं।

data Name = Name { first, middle, last :: String } 
instance Default Name where def = Name def def def 

esquire [email protected](Name { last = l }) = n { last = l ++ ", Esquire" } 

कौन सा आप इन दो तरह कॉल कर सकते हैं उदाहरण के लिए,:

esquire def { first = "Daniel", middle = "M.", last = "Wagner" } 
esquire def { last = "Wagner", first = "Daniel" } 
6

अन्य उत्तर जबकि रहे हैं "एक (थोड़ा बदसूरत) वर्ग बारे में" और "एक योग प्रकार के माध्यम से प्रकार एकजुट"। मैं एक बहुत ही हास्कली सुझाव देने जा रहा हूं और हर किसी को याद दिलाता हूं कि यदि आप इसके लिए पूछते हैं तो हास्केल में गतिशील टाइपिंग होती है।

रन-टाइम पर, बस ASK क्या प्रकार है और प्रत्येक प्रकार के लिए अपना ऑपरेशन अलग करें। यह डेटा का उपयोग कर किया जा सकता है। टाइप करने योग्य मॉड्यूल।

उदाहरण के लिए:

import Data.Typeable 
import Data.Data 

combine :: (Typeable a, Typeable b) => a -> b -> Int 
combine a b 
    | typeOf a == strTy && typeOf b == intTy = 
     case (cast a, cast b) of 
      (Just str,Just i) -> read $ str ++ show (i :: Int) 
    | typeOf a == intTy && typeOf b == strTy = 
     case (cast a, cast b) of 
      (Just i,Just str) -> read $ show (i :: Int) ++ str 
    | otherwise = error "You said you wanted an exception..." 
where 
strTy = typeOf "" 
intTy = typeOf (undefined :: Int) 

और एक टेस्ट रन पता चलता है:

> combine "100" (500 :: Int) 
100500 

आप अपवाद तो महान से छुटकारा पाने चाहते हैं! हम कोड हो सकता है कि इकाई का उपयोग कर हम यह कर रहे हों, जबकि साफ कर सकते हैं:

combine2 :: (Typeable a, Typeable b) => a -> b -> Maybe Int 
combine2 a b 
    | typeOf a == strTy && typeOf b == intTy = do 
     a' <- cast a 
     b' <- cast b 
     return $ read $ a' ++ show (b' :: Int) 
    | typeOf a == intTy && typeOf b == strTy = do 
     a' <- cast a 
     b' <- cast b 
     return $ read $ show (a' :: Int) ++ b' 
    | otherwise = Nothing 
where 
strTy = typeOf "" 
intTy = typeOf (undefined :: Int) 

और बस की बिल्ली के लिए कुछ और उत्पादन:

> combine2 "500" (5 :: Int) 
Just 5005 
> combine (5 :: Int) "500" 
5500 
> combine2 (5 :: Int) "500" 
Just 5500 
> combine "500" "300" 
*** Exception: You said you wanted an exception... 
> combine2 "500" "300" 
Nothing 

और बस हो गया! हम जोड़ सकते हैं कि हम कितने प्रकार के संयोजन चाहते हैं, बस अंतिम otherwise गार्ड से पहले अपने वांछित संचालन को सम्मिलित करें।

2

एक और बदसूरत और निराशाजनक समाधान:

{-# FlexibleInstances, TypeSynonymInstances #-} 

class IntOrString a where 
    toString :: a -> String 
    typeID :: a -> Int 

instance IntOrString String where 
    toString s = s 
    typeID _ = 0  

instance IntOrString Int where 
    toString x = show x 
    typeID _ = 1  

combine a b | typeID a + typeID b == 1 = toString a ++ toString b 
combine _ _ = error "WTF?!?" 

combine "100" (500::Int) --type needed because of monomorphism restriction 
संबंधित मुद्दे