2016-01-20 5 views
5

में टाइपक्लास और विरासत समस्या को परिभाषित करने का यह दूसरा प्रयास है, मैं इसके चारों ओर अपना सिर नहीं प्राप्त कर सकता।स्कालज़

मैं बीजगणितीय प्रकार को परिभाषित करने और उस पर एक साधारण टाइपक्लास परिभाषित करने में सक्षम होना चाहता हूं, मान लें कि Show। हास्केल में मुझे क्या करना:

data Tree a = EmptyTree | Node a deriving (Show) 

अब, अगर मैं EmptyTree टाइप - Haskell यह दिखा सकते हैं, तो यह Show के अंतर्गत आता है।

अब मैं स्केला में भी ऐसा ही करने की कोशिश कर रहा हूँ:

sealed abstract class Tree[+T] 
case object EmptyTree extends Tree[Nothing] 
case class Node[T](value: T) extends Tree[T] 

तो मैं उसके चारों ओर Show को परिभाषित:

implicit def show[T] = Show.showA[Tree[T]] 

मैं println((EmptyTree : Tree[Int]).show) कर सकते हैं। लेकिन मैं ऐसा नहीं कर सकते println(EmptyTree.show) (प्रतिक्रिया value show is not a member of object EmptyTree है)

मैं अतिरिक्त लिखने के लिए है:

implicit class MyShowOps[A, +T <: Tree[A]](t: T) { 
    def showMy(implicit ev: Show[Tree[A]]): String = ev.shows(t) 
} 

और उसके बाद ही मैं क्या कर सकते हैं println(EmptyTree.showMy)

यह अभी भी सही नहीं है, तो मेरा मानना ​​है कि या तो मैं गलत काम करने की कोशिश कर रहा हूं और मुझे Show को इस तरह लागू नहीं करना चाहिए और मुझे अपने निर्माण का उपयोग केवल Tree[T] के रूप में करना चाहिए या मुझे स्कालाज़ से उचित निर्माण याद आ रहा है।

उत्तर

4

एडीटी के स्कैला का प्रतिनिधित्व हास्केल से अलग है जिसमें इसके रचनाकारों का अपना प्रकार है। यह आंशिक रूप से व्यावहारिक अंतःक्रियाशीलता के बारे में है- सबटाइपिंग का उपयोग जेवीएम पर प्राकृतिक है- और इसमें both advantages and disadvantages है।

आप नुकसान में से एक में भाग रहे हैं, जिसमें यह है कि रचनात्मक प्रकार के रूप में स्थिर रूप से टाइप किए गए मान अक्सर टाइप अनुमान और अंतर्निहित संकल्प को जटिल करते हैं।

प्रकार वर्ग उदाहरणों स्थिर हल कर रहे हैं, और अपने मामले में विशेष रूप Show contravariant नहीं है, इसलिए Tree[T] के लिए एक उदाहरण EmptyTree.type के लिए एक उदाहरण नहीं है।

import scalaz.Show, scalaz.syntax.show._ 

sealed abstract class Tree[+T] 

object Tree { 
    private[this] case object EmptyTree extends Tree[Nothing] 
    private[this] case class Node[T](value: T) extends Tree[T] 

    val emptyTree: Tree[Nothing] = EmptyTree 
    def node[T](value: T): Tree[T] = Node(value) 

    implicit def show[T]: Show[Tree[T]] = Show.showA[Tree[T]] 
} 

अब आप Tree.emptyTree.show लिख सकते हैं: Scalaz नजरिए से सबसे मुहावरेदार समाधान स्मार्ट कंस्ट्रक्टर्स कि एडीटी प्रकार वापसी प्रदान करना है।

ध्यान दें कि यह समस्या भी सरल संदर्भों में बदल जाती है। उदाहरण के लिए, मान लीजिए हम संचायक के रूप में एक Option के साथ एक सूची से अधिक गुना करना चाहते हैं:

scala> List(1, 2, 3).foldLeft(Some(0))((acc, i) => acc.map(_ + i)) 
<console>:11: error: type mismatch; 
found : Option[Int] 
required: Some[Int] 
     List(1, 2, 3).foldLeft(Some(0))((acc, i) => acc.map(_ + i)) 
                 ^

क्योंकि Some(0) के लिए अनुमानित प्रकार Some[Int], नहीं Option[Int] है, प्रकार पैरामीटर कि foldLeft विधि लिए लगाए गए अनुमान है के लिए अत्यंत सीमित है map का नतीजा।

यह अच्छा होगा यदि मानक पुस्तकालय इस तरह के मामलों के लिए प्रदान की Option.none और Option.some "कंस्ट्रक्टर्स" हो सकता है, लेकिन यह आप या तो पहला तर्क पर एक प्रकार एनोटेशन डाल या Scalaz के none की तरह कुछ का उपयोग करने के तो और नहीं है, some:

scala> import scalaz._, Scalaz._ 
import scalaz._ 
import Scalaz._ 

scala> List(1, 2, 3).foldLeft(some(0))((acc, i) => acc.map(_ + i)) 
res0: Option[Int] = Some(6) 

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

+0

मैंने स्केलज़ स्रोतों में 'वैल खाली ट्री: ट्री [कुछ भी नहीं] .. जैसे पैटर्न देखा है, लेकिन यह समझ में नहीं आया कि ऐसा क्यों किया गया। अब यह मुझे स्पष्ट है। अभी भी कुछ ऐसा नहीं है जो मुझे समझ में नहीं आता है, क्या कोई विशेष कारण है कि स्केलज़ 'शोओप्स' को परिभाषित नहीं किया गया था जैसा मैंने किया था? यह 'खाली ट्री' और 'नोड [टी] ' – Archeg

+0

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

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