2016-03-30 6 views
17

को देखते हुए निम्नलिखित वर्गों इनपुट प्रकार पर निर्भर करता है परिभाषित करने के लिए:कैसे एक समारोह जिसका उत्पादन प्रकार

case class AddRequest(x: Int, y: Int) 
case class AddResponse(sum: Int) 
case class ToUppercaseRequest(str: String) 
case class ToUppercaseResponse(upper: String) 

कैसे मैं एक typesafe ढंग से कुछ समारोह परिभाषित करते हैं:

def process(req: ???): ??? 

इस तरह की है कि निम्न सच धारण करना चाहिए:

val r1: AddResponse = process(AddRequest(2, 3)) 
val r2: ToUppercaseResponse = process(ToUppercaseRequest("aaa")) 

इसके अलावा, निम्नलिखित चाहिए नहीं संकलन:

val r3 = process("somestring") 

उत्तर

27

यह पूरी तरह से संभव है और स्कैला में पूरी तरह से उचित बात है। इस तरह की चीज पूरी तरह से बेकार है, उदाहरण के लिए, और कुछ समान (लेकिन कम सिद्धांत) स्प्रे, आदि में दिखाए गए चुंबक पैटर्न का आधार है

अद्यतन: ध्यान दें कि निम्न समाधान मानता है कि "दिया गया निम्नलिखित वर्ग "का अर्थ है कि आप केस कक्षाओं को स्वयं छूना नहीं चाहते हैं। यदि आपको परवाह नहीं है, तो नीचे दिए गए उत्तर का दूसरा भाग देखें।

case class AddRequest(x: Int, y: Int) 
case class AddResponse(sum: Int) 
case class ToUppercaseRequest(str: String) 
case class ToUppercaseResponse(upper: String) 

trait Processable[In] { 
    type Out 
    def apply(in: In): Out 
} 

और फिर कुछ प्रकार वर्ग उदाहरणों:

object Processable { 
    type Aux[I, O] = Processable[I] { type Out = O } 

    implicit val toUppercase: Aux[ToUppercaseRequest, ToUppercaseResponse] = 
    new Processable[ToUppercaseRequest] { 
     type Out = ToUppercaseResponse 
     def apply(in: ToUppercaseRequest): ToUppercaseResponse = 
     ToUppercaseResponse(in.str.toUpperCase) 
    } 

    implicit val add: Aux[AddRequest, AddResponse] = 
    new Processable[AddRequest] { 
     type Out = AddResponse 
     def apply(in: AddRequest): AddResponse = AddResponse(in.x + in.y) 
    } 
} 

और अब आप को परिभाषित कर सकते process इस प्रकार के वर्ग का उपयोग कर

तुम एक प्रकार वर्ग कि उत्पादन प्रकार के लिए इनपुट प्रकार नक्शे चाहते हैं :

def process[I](in: I)(implicit p: Processable[I]): p.Out = p(in) 

जो वांछित काम करता है (उचित सेंट पर ध्यान दें atic प्रकार):

scala> val res: ToUppercaseResponse = process(ToUppercaseRequest("foo")) 
res: ToUppercaseResponse = ToUppercaseResponse(FOO) 

scala> val res: AddResponse = process(AddRequest(0, 1)) 
res: AddResponse = AddResponse(1) 

लेकिन यह मनमाना प्रकार पर काम नहीं करता: यहां तक ​​कि है एक रास्ता निर्भर प्रकार का उपयोग करने के लिए (आप में सक्षम होना चाहिए बस के लिए नहीं

scala> process("whatever") 
<console>:14: error: could not find implicit value for parameter p: Processable[String] 
     process("whatever") 
      ^

आप करते हैं टाइप क्लास पर दो प्रकार के पैरामीटर), लेकिन यह process का उपयोग करके थोड़ा अच्छा है, उदाहरण के लिए आपको टाइप पैरामीटर को स्पष्ट रूप से प्रदान करना होगा।


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

trait Input[Out] { 
    def computed: Out 
} 

case class AddRequest(x: Int, y: Int) extends Input[AddResponse] { 
    def computed: AddResponse = AddResponse(x + y) 
} 
case class AddResponse(sum: Int) 

case class ToUppercaseRequest(str: String) extends Input[ToUppercaseResponse] { 
    def computed: ToUppercaseResponse = ToUppercaseResponse(str.toUpperCase) 
} 
case class ToUppercaseResponse(upper: String) 

def process[O](in: Input[O]): O = in.computed 

और फिर:

scala> process(AddRequest(0, 1)) 
res9: AddResponse = AddResponse(1) 

scala> process(ToUppercaseRequest("foo")) 
res10: ToUppercaseResponse = ToUppercaseResponse(FOO) 

कौन सा बहुरूपता की तरह (पैरामीट्रिक या तदर्थ) आप पसंद करते हैं चाहिए पूरी तरह से आप पर निर्भर है। यदि आप मनमानी प्रकारों के बीच मैपिंग का वर्णन करने में सक्षम होना चाहते हैं, तो एक प्रकार की कक्षा का उपयोग करें। यदि आप परवाह नहीं करते हैं, या सक्रिय रूप से नहीं चाहते हैं कि यह ऑपरेशन सबटाइपिंग का उपयोग करके मनमानी प्रकारों के लिए उपलब्ध हो।

+0

[पैरामीट्रिक पॉलिमॉर्फिज्म] के उप-समूह [https://en.wikipedia.org/wiki/Polymorphism_ (computer_science) #Subtyping) का दूसरा मामला नहीं है [https://en.wikipedia.org/ wiki/Polymorphism_ (computer_science) #Parametric_polymorphism)? पैरामीट्रिक ऐसा मामला होना चाहिए जब कोई विधि किसी प्रकार पर निर्भर न हो, जैसे कि सूची [टी] पर लंबाई()? – slouc

+0

@slouc किस अर्थ में? तथ्य यह है कि उदा। 'दाएं' पर 'या तो [एल, आर]' एक 'दाएं प्रक्षेपण' लौटाता है [एल, आर] 'पैरामीट्रिक बहुरूपता का एक उदाहरण है, उप प्रकार नहीं। –

+0

मेरा मतलब है, 'AddRequest' और' ToUppercaseRequest' 'इनपुट [टी] 'बढ़ाएं, विधि' प्रक्रिया' 'इनपुट' का एक उदाहरण लेती है और वास्तव में 'इनपुट' (अर्थात 'AddRequest' और' ToUppercaseRequest' के उप-वर्गों को पारित किया जा रहा है))। यह उप प्रकार है, है ना? – slouc

3

आप अनुरोध के लिए एक आम विशेषता है, और जवाब के लिए एक आम विशेषता जहां अनुरोध प्रकार विशिष्ट प्रतिक्रिया प्रकार के लिए परिभाषित किया गया है परिभाषित कर सकते हैं:

trait Request[R <: Response] 
trait Response 

case class AddRequest(x: Int, y: Int) extends Request[AddResponse] 
case class AddResponse(sum: Int) extends Response 
case class ToUppercaseRequest(str: String) extends Request[ToUppercaseResponse] 
case class ToUppercaseResponse(upper: String) extends Response Response[ToUppercaseRequest] 

फिर, process हस्ताक्षर होगा:

def process[A <: Request[B], B <: Response](req: A): B 

जब आप process कहते हैं, आप तो यह है कि लौटे प्रकार तुम क्या विस्तार है स्पष्ट रूप प्रकारों को परिभाषित करना होगा यह होना चाहिए - इसे विशेष रूप से पर्याप्त नहीं किया जा सकता है:

val r1: AddResponse = process[AddRequest, AddResponse](AddRequest(2, 3)) 
val r2: ToUppercaseResponse = process[ToUppercaseRequest, ToUppercaseResponse](ToUppercaseRequest("aaa")) 
+0

हम्म। लेकिन अगर मैं 'प्रक्रिया' को 'AddRequest' तर्क के साथ कॉल करता हूं, तो यह' प्रतिक्रिया [AddRequest] 'वापस कर देगा। मुझे इसके बजाय 'AddResponse' वापस करने की आवश्यकता है जिससे मैं 'sum' पर काम कर सकता हूं। – jvliwanag

+0

क्षमा करें - इसे मिश्रित करें, अभी तय किया गया है: जब इसे कॉल किया जाता है तो विधि के स्पष्ट टाइपिंग के साथ, यह कोड सफलतापूर्वक चलाता है। –

+0

एचएम। क्या आप 'प्रक्रिया' के लिए भी एक कार्यान्वयन लिखना चाहते हैं? – jvliwanag

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