2011-09-08 9 views
9

में पारस्परिक रूप से निर्भर डिफ़ॉल्ट विधि कार्यान्वयन को शामिल करना मैं कुछ गुणों के साथ एक विशेषता को परिभाषित करना चाहता हूं जिसमें एक अच्छी तरह से परिभाषित संबंध है - उदाहरण के लिए, मान लें कि a * b = c। विचार यह है कि इस विशेषता के कार्यान्वयन इनमें से दो प्रदान कर सकते हैं और स्वचालित रूप से प्राप्त तीसरी संपत्ति के लिए एक एक्सेसर है।स्कैला

( यह हास्केल के प्रकार वर्ग के रूप में एक ही सुविधा है, अगर मैं उन सही ढंग से है, जहां अगर आप Ord से < परिभाषित याद है, >=! . < के रूप में लागू किया जाएगा - हालांकि आप शेष के रूप में इतने लंबे समय के किसी भी कार्य के सबसेट निर्धारित कर सकते हैं । अनुमान लगाया जा सकता है) (मैं सही ढंग से हास्केल के प्रकार कक्षाओं याद नहीं)

भोली दृष्टिकोण वास्तव में काफी अच्छी तरह से काम करता है:।

trait Foo { 
    // a * b = c 
    def a: Double = c/b 
    def b: Double = c/a 
    def c: Double = a * b 
} 

class FooOne(override val a: Double, override val b: Double) extends Foo 
class FooTwo(override val a: Double, override val c: Double) extends Foo 

यहाँ, कार्यान्वयन FooOne और FooTwoFoo के पूर्ण कार्यान्वयन हैं, और अपेक्षित व्यवहार करते हैं। अब तक सब ठीक है; यह दृष्टिकोण वर्गों को दो गुणों को परिभाषित करने और तीसरे को "मुफ्त में" प्राप्त करने की अनुमति देता है।

हालांकि, बातें करता है, तो एक एक तृतीय श्रेणी को परिभाषित करता है कम गुलाबी देखने के लिए शुरू:

class FooFail(override val a: Double) extends Foo 

यह ठीक संकलित - हालांकि, यह एक ढेर अतिप्रवाह कारण होगा अगर इसके b या c तरीकों कभी मूल्यांकन किया जाता है।


तो भोली दृष्टिकोण हास्केल के प्रकार वर्ग दृष्टिकोण के अनुमान पहलू देता है, लेकिन हम संकलन समय सुरक्षा की जरूरत नहीं है। यदि मैं कक्षाओं को कार्यान्वित करके दो तरीकों से कम परिभाषित किया गया है तो संकलक शिकायत करने के लिए मैं क्या चाहता हूं। स्पष्ट रूप से वर्तमान वाक्यविन्यास यहां पर्याप्त नहीं है; हमें अमूर्त मानने के तरीकों की आवश्यकता होती है, यद्यपि एक डिफ़ॉल्ट कार्यान्वयन के साथ प्रयोग किया जा सकता है, यदि केवल और यदि निर्भर विधियां गैर-सारणी हों।

क्या स्कैला इसे परिभाषित करने के लिए उपयुक्त अर्थशास्त्र का पर्दाफाश करता है? (अगर मुझे परिभाषित करने का कुछ हद तक चौराहे वाला तरीका है, तो मुझे कोई समस्या नहीं है, union types के समान, क्योंकि मुझे भाषा में इसके लिए किसी प्रथम श्रेणी के समर्थन के बारे में पता नहीं है)।

यदि नहीं, तो मैं भद्दा दृष्टिकोण के साथ करूँगा और बस अपनी कक्षाओं को सावधानी से परिभाषित और परीक्षण करूँगा। लेकिन मुझे सच में लगता है कि यह ऐसा कुछ है जो टाइप सिस्टम को पकड़ने में सक्षम होना चाहिए (आखिरकार - यह रूबी नहीं है। :))।

+2

जब तक मैं पूरी तरह से गलत नहीं मानता, तब तक हास्केल एक ही समस्या के साथ एक ही भद्दा दृष्टिकोण का उपयोग करता है। –

+0

@Alexey - दिलचस्प टिप्पणी। यह थोड़ी देर हो गया है, लेकिन मुझे याद है कि यदि आपने पर्याप्त तरीकों को परिभाषित नहीं किया है तो आपको लाइनों के साथ सभी विधियों को प्राप्त करना संभव नहीं था, इस लाइन के साथ एक कंपाइलर/दुभाषिया त्रुटि प्राप्त होगी। हो सकता है कि मैं इसे पुन: उत्पन्न करने की कोशिश करूंगा, और प्रेरणा के लिए हास्केल इसे कैसे करता हूं, इस पर पढ़ता हूं। –

+0

ठीक है, इसने हास्केल में इसका परीक्षण किया है, यह वास्तव में एक ही समस्या से पीड़ित है (यह स्कैला की स्थिति के बराबर है जिसमें यह केवल पूरी तरह से अमूर्त तरीकों के बारे में चेतावनी देता है)। उस ने कहा, सवाल अभी भी खड़ा है, यद्यपि किसी अन्य भाषा में उदाहरण के बिना। –

उत्तर

8

उपयोग implicits:

object test { 
    case class A(v : Double) 
    case class B(v : Double) 
    case class C(v : Double) 

    implicit def a(implicit b : B, c : C) = A(c.v/b.v) 
    implicit def b(implicit a : A, c : C) = B(c.v/a.v) 
    implicit def c(implicit a : A, b : B) = C(a.v * b.v) 

    def foo(implicit a : A, b : B, c : C) = 
    a + ", " + b + ", " + c 

    // Remove either of these and it won't compile 
    implicit val aa = A(3) 
    implicit val bb = B(4) 

    def main(args : Array[String]) { 
    println(foo) 
    } 
} 
+0

बहुत ही रोचक दृष्टिकोण - मेरी टिप्पणी के अनुसार मुझे लगता है कि संकल्पक पर्याप्त जांच के लिए संकलक प्राप्त करने में महत्वपूर्ण होंगे। यह एक शर्म की बात है कि उपभोक्ता सिर्फ 'वैल बी = 5' घोषित नहीं कर सकते हैं, हालांकि। मुझे आश्चर्य है कि क्या यह लक्षणों की एक और आंतरिक परत के माध्यम से मालिश किया जा सकता है। –

5

हास्केल में आप सुरक्षा कैसे प्राप्त करते हैं? मैं भाषा से बहुत परिचित नहीं हूं, लेकिन मैं

data Func = Func (Int -> Int) 
instance Eq Func 
instance Ord Func 

compared = Func (\i -> i-1) < Func (\i -> i+1) 

और तुलनात्मक मूल्यांकन करते समय एक स्टैक ओवरफ़्लो प्राप्त कर सकता हूं।

मैं स्कैला में एक कामकाज की कल्पना कर सकता हूं लेकिन एक कमजोर व्यक्ति हूं। सबसे पहले, फू छोड़ पूरी तरह से अमूर्त

trait Foo { def a: Double; def b: Double; def c: Double } 

फिर प्रत्येक विधि परिभाषा संयोजन की अनुमति दी

trait FooWithAB extends Foo {def c : Double = a * b} 
trait FooWithAC extends Foo {def b : Double = c/a} 
trait FooWithBC extends Foo {def a : Double = c/b} 

FooOne और FooTwo विशेषता में से एक में मिश्रण करना होगा के लिए mixin लक्षण पैदा करते हैं।FooFail में, कुछ भी आपको उनमें से दो में मिश्रण करने से रोकता है, और अभी भी असफल हो जाता है, लेकिन आपको कुछ हद तक चेतावनी दी गई है।

है, तो आप को परिभाषित नहीं कर सकते हैं प्रेत प्रकार का एक प्रकार के साथ एक कदम आगे जाने के लिए और उनमें से दो मिश्रण न करे,

trait Foo { 
    type t; 
    def a: Double; def b: Double; def c: Double 
} 
trait FooWithAB extends Foo {type t = FooWithAB; def c : Double = a * b} 
trait FooWithAC extends Foo {type t = FooWithAC; def b : Double = c/a} 
trait FooWithBC extends Foo {type t = FooWithBC; def c : Double = c/b} 

यह FooWithXX के दो मिश्रण को रोकने के लिए संभव है

class FooFail(val a: Double) extends FooWithAC with FooWithAB 
+0

अच्छा बिंदु - मुझे संदेह है कि किसी भी समाधान में 'फू' में पूरी तरह से अमूर्त विधियों को छोड़ने और फिर * कहीं * से डिफ़ॉल्ट परिभाषाओं में मिश्रण शामिल होगा। प्रेत प्रकार का दृष्टिकोण दिलचस्प है, हालांकि यह एक शर्म की बात है कि क्लंकनेस उन उपभोक्ताओं के सामने आती है जिन्हें स्पष्ट रूप से विशेषता में मिश्रण करना होता है। शायद निहित रूपांतरण इस तरह से काम कर सकते हैं, हम्म ... –

2

एक समाधान की तुलना में थोड़ा कमजोर क्या आप चाहते हो सकता है पीछा कर रहा है:

trait Foo { 
    def a : Double 
    def b : Double 
    def c : Double 
} 

// Anything with two out of three can be promoted to Foo status. 
implicit def ab2Foo(ab : { def a : Double; def b : Double }) = 
    new Foo { val a = ab.a; val b = ab.b; def c = ab.a * ab.b } 
implicit def bc2Foo(bc : { def b : Double; def c : Double }) = 
    new Foo { val a = bc.c/bc.b; val b = bc.b; def c = bc.c } 
implicit def ac2Foo(ac : { def a : Double; def c : Double }) = 
    new Foo { val a = ac.a; val b = ac.c/ac.a; def c = ac.c } 

इधर, तीन एक से दो के साथ किसी भी वर्ग, ख, ग तरीकों देखी और एक फू के रूप में इस्तेमाल किया जा सकता। उदाहरण के लिए:

case class AB(a : Double, b : Double) 
AB(5.0, 7.1).c // prints 35.5 

लेकिन अगर आप उदाहरण के लिए प्रयास करें:

case class ABC(a : Double, b : Double, c : Double) 
val x : Foo = ABC(1.0, 2.0, 3.0) 

... आप एक "अस्पष्ट अस्पष्ट" त्रुटि मिलती है।

मुख्य समस्या w.r.t आपका मूल विवरण यह है कि कक्षाएं Foo से उचित रूप से प्राप्त नहीं होती हैं, जो कि यदि आप अन्य विधियों का पुन: उपयोग करना चाहते हैं तो समस्या हो सकती है। आप इसके आसपास काम कर सकते हैं हालांकि एक अन्य विशेषता FooImpl जिसमें इन अन्य विधियों को शामिल किया गया है, और FooImpl के उपप्रकारों में अंतर्निहित रूपांतरणों को प्रतिबंधित करें।

+0

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