2014-09-18 6 views
16

मैं कल रात बहुत देर तक इस बेकार मुद्दे को समझने की कोशिश कर रहा था और मुझे डर है कि अगर मैं इसे बंद नहीं कर पाता हूं तो यह मेरी शाम को खाने जा रहा है मेरी छाती, तो यहाँ जाता है।अजीब व्यवहार केस वर्गों को विषम सूचियों में बदलने के लिए निरंतर सूची में बदलने की कोशिश कर रहा है

इस कम से कम संस्करण में मैं सिर्फ heterogeneous सूचियों में एक प्रकार वर्ग कि रिकर्सिवली मामले कक्षाओं में परिवर्तित कर देंगे परिभाषित करने हूँ:

import shapeless._ 

trait DeepHLister[R <: HList] extends DepFn1[R] { type Out <: HList } 

trait LowPriorityDeepHLister { 
    type Aux[R <: HList, Out0 <: HList] = DeepHLister[R] { type Out = Out0 } 

    implicit def headNotCaseClassDeepHLister[H, T <: HList](implicit 
    dht: DeepHLister[T] 
): Aux[H :: T, H :: dht.Out] = new DeepHLister[H :: T] { 
    type Out = H :: dht.Out 
    def apply(r: H :: T) = r.head :: dht(r.tail) 
    } 
} 

object DeepHLister extends LowPriorityDeepHLister { 
    implicit object hnilDeepHLister extends DeepHLister[HNil] { 
    type Out = HNil 
    def apply(r: HNil) = HNil 
    } 

    implicit def headCaseClassDeepHLister[H, R <: HList, T <: HList](implicit 
    gen: Generic.Aux[H, R], 
    dhh: DeepHLister[R], 
    dht: DeepHLister[T] 
): Aux[H :: T, dhh.Out :: dht.Out] = new DeepHLister[H :: T] { 
    type Out = dhh.Out :: dht.Out 
    def apply(r: H :: T) = dhh(gen.to(r.head)) :: dht(r.tail) 
    } 

    def apply[R <: HList](implicit dh: DeepHLister[R]): Aux[R, dh.Out] = dh 
} 

के लिए इसे बाहर की कोशिश करते हैं! सबसे पहले हम कुछ मामले वर्गों की जरूरत है:

case class A(x: Int, y: String) 
case class B(x: A, y: A) 
case class C(b: B, a: A) 
case class D(a: A, b: B) 

और फिर (ध्यान दें कि मैं इस की खातिर नहीं एक पूरी तरह से पढ़ने योग्य नहीं गड़बड़ होने के लिए प्रकार वाक्य रचना को साफ कर दिया है):

scala> DeepHLister[A :: HNil] 
res0: DeepHLister[A :: HNil]{ 
    type Out = (Int :: String :: HNil) :: HNil 
} = [email protected] 

scala> DeepHLister[B :: HNil] 
res1: DeepHLister[B :: HNil] { 
    type Out = (
    (Int :: String :: HNil) :: (Int :: String :: HNil) :: HNil 
) :: HNil 
} = [email protected] 

scala> DeepHLister[C :: HNil] 
res2: DeepHLister[C :: HNil] { 
    type Out = (
    ((Int :: String :: HNil) :: (Int :: String :: HNil) :: HNil) :: 
    (Int :: String :: HNil) :: 
    HNil 
) :: HNil 
} = [email protected] 

अब तक तो अच्छा। लेकिन तब:

scala> DeepHLister[D :: HNil] 
res3: DeepHLister[D :: HNil] { 
    type Out = ((Int :: String :: HNil) :: B :: HNil) :: HNil 
} = [email protected] 

B परिवर्तित नहीं हुआ। अगर हम -Xlog-implicits पर बारी यह पिछले संदेश है:

<console>:25: this.DeepHLister.headCaseClassDeepHLister is not a valid implicit value for DeepHLister[shapeless.::[B,shapeless.HNil]] because: 
hasMatchingSymbol reported error: diverging implicit expansion for type DeepHLister[this.Repr] 
starting with method headNotCaseClassDeepHLister in trait LowPriorityDeepHLister 
       DeepHLister[D :: HNil] 
         ^

कौन मुझ को समझ में headCaseClassDeepHListerDeepHLister[B :: HNil] ठीक उत्पन्न करने के लिए सक्षम होना चाहिए नहीं है, और यदि आप इसे सीधे पूछना होता है।

यह 2.10.4 और 2.11.2 दोनों पर होता है, और 2.0.0 रिलीज और मास्टर दोनों के साथ होता है। मुझे पूरा यकीन है कि यह एक बग होना है, लेकिन मैं इस संभावना से बाहर नहीं हूं कि मैं कुछ गलत कर रहा हूं। क्या किसी ने इससे पहले कुछ देखा है? क्या मेरे तर्क या Generic पर कुछ प्रतिबंध के साथ कुछ गड़बड़ है, मुझे याद आ रही है?

ठीक है, सुनने के लिए धन्यवाद-शायद अब मैं एक किताब या कुछ पढ़ सकता हूं।

+0

मुझे 'दीपलिस्टर [बी :: एचएनआईएल]' के साथ एक ही समस्या है। मैंने बस 5 मिनट पहले कोड कॉपी किया था, इसलिए मैं आगे की जांच करूंगा। – EECOLOR

+0

यह व्हाइटबॉक्स मैक्रोज़ के साथ बहुत आसान होगा। –

+1

@ GuillaumeMassé, ठीक है, निश्चित रूप से, लेकिन लक्ष्य मैक्रोज़ के उपयोग को बेकार द्वारा प्रदान किए गए कुछ मौलिक लोगों तक सीमित करना है। –

उत्तर

6

यह अब हाल ही में निराकार-2.1.0-SNAPSHOT बनाता का उपयोग कर अधिक या कम के रूप में लिखा काम करता है, और इस सवाल में नमूने के एक करीबी रिश्तेदार है example के रूप में जोड़ा गया है।

मूल के साथ समस्या यह है कि एक

Generic में से प्रत्येक के विस्तार DeepHLister प्रकार वर्ग उदाहरणों में से निहित संकल्प में एक नया HList प्रकार का परिचय और, सिद्धांत रूप में, एक HList प्रकार है कि करने के लिए, लेकिन कुछ तुलना में अधिक जटिल संबंधित है उत्पादन कर सकता है पहले एक ही संकल्प के दौरान देखा गया प्रकार। यह स्थिति विचलन चेकर की यात्रा करती है और संकल्प प्रक्रिया को रोकती है।

क्यों इस D के लिए लेकिन C स्काला के typechecker के कार्यान्वयन के विवरण में गुप्त है, लेकिन एक प्राथमिक अनुमान के लिए, के लिए नहीं होता है के समुचित कारण, दूसरों से अलग है कि C के लिए संकल्प के दौरान हम देखते हैं B (बड़ा) A (छोटे) से पहले तो विचलन चेकर खुश है कि हमारे प्रकार अभिसरण कर रहे हैं; D के लिए संकल्प के दौरान हम B (बड़ा) से पहले A (छोटे) देखते हैं, इसलिए विचलन चेकर (रूढ़िवादी) बेल्स।

आकारहीन 2.1.0 में इसके लिए फिक्स हाल ही में Lazy प्रकार का कन्स्ट्रक्टर और संबंधित अंतर्निहित मैक्रो इंफ्रास्ट्रक्चर है। यह विचलन पर अधिक उपयोगकर्ता नियंत्रण की अनुमति देता है और पुनरावर्ती निहित मूल्यों का निर्माण करने के लिए अंतर्निहित संकल्प के उपयोग का समर्थन करता है जो रिकर्सिव प्रकारों के लिए प्रकार क्लास उदाहरणों को स्वचालित रूप से प्राप्त करने की क्षमता के लिए महत्वपूर्ण हैं। इसका कई उदाहरण बेकार कोड बेस में पाया जा सकता है, विशेष रूप से पुनर्निर्मित प्रकार के वर्ग व्युत्पन्न बुनियादी ढांचे और स्क्रैप आपके बॉयलरप्लेट कार्यान्वयन, जिसे अब समर्पित मैक्रो समर्थन की आवश्यकता नहीं है, लेकिन पूरी तरह से Generic और Lazy प्राइमेटिव के संदर्भ में लागू किया जाता है। इन तंत्रों के विभिन्न अनुप्रयोग बेकार उदाहरण उप-प्रोजेक्ट में पाए जा सकते हैं।

+0

क्या आकारहीन 2.3.2 के लिए इसमें कोई बदलाव है? उदाहरण यह संकलित नहीं करता है कि यह 2 हेड * अंतर्निहित रिटर्न प्रकारों के बारे में शिकायत करता है ... मैं 2.11.11 – Damian

+0

का उपयोग कर रहा हूं यदि आप 2.11.11 के साथ एक त्रुटि पुन: उत्पन्न कर सकते हैं तो कृपया इसे बेकार समस्या ट्रैकर पर रिपोर्ट करें। –

6

मैंने थोड़ा अलग दृष्टिकोण लिया।

trait CaseClassToHList[X] { 
    type Out <: HList 
} 

trait LowerPriorityCaseClassToHList { 
    implicit def caseClass[X](implicit gen: Generic[X]): CaseClassToHList[X] { 
    type Out = generic.Repr 
    } = null 
} 

object CaseClassToHList extends LowerPriorityCaseClassToHList { 
    type Aux[X, R <: HList] = CaseClassToHList[X] { type Out = R } 

    implicit def caseClassWithCaseClasses[X, R <: HList](
    implicit toHList: CaseClassToHList.Aux[X, R], 
    nested: DeepHLister[R]): CaseClassToHList[X] { 
    type Out = nested.Out 
    } = null 
} 

trait DeepHLister[R <: HList] { 
    type Out <: HList 
} 

object DeepHLister { 

    implicit def hnil: DeepHLister[HNil] { type Out = HNil } = null 

    implicit def caseClassAtHead[H, T <: HList](
    implicit head: CaseClassToHList[H], 
    tail: DeepHLister[T]): DeepHLister[H :: T] { 
    type Out = head.Out :: tail.Out 
    } = null 

    def apply[X <: HList](implicit d: DeepHLister[X]): d.type = null 
} 

निम्न कोड के साथ परीक्षण किया गया:

case class A(x: Int, y: String) 
case class B(x: A, y: A) 
case class C(b: B, a: A) 
case class D(a: A, b: B) 

object Test { 

    val z = DeepHLister[HNil] 
    val typedZ: DeepHLister[HNil] { 
    type Out = HNil 
    } = z 

    val a = DeepHLister[A :: HNil] 
    val typedA: DeepHLister[A :: HNil] { 
    type Out = (Int :: String :: HNil) :: HNil 
    } = a 

    val b = DeepHLister[B :: HNil] 
    val typedB: DeepHLister[B :: HNil] { 
    type Out = ((Int :: String :: HNil) :: (Int :: String :: HNil) :: HNil) :: HNil 
    } = b 

    val c = DeepHLister[C :: HNil] 
    val typedC: DeepHLister[C :: HNil] { 
    type Out = (((Int :: String :: HNil) :: (Int :: String :: HNil) :: HNil) :: (Int :: String :: HNil) :: HNil) :: HNil 
    } = c 

    val d = DeepHLister[D :: HNil] 
    val typedD: DeepHLister[D :: HNil] { 
    type Out = ((Int :: String :: HNil) :: ((Int :: String :: HNil) :: (Int :: String :: HNil) :: HNil) :: HNil) :: HNil 
    } = d 
} 
+0

हे @EECOLOR, धन्यवाद- मैं इस पर ध्यान देने में अधिक समय बिताने का मतलब रहा हूं, और यह नहीं पता था कि बक्षीस की समयसीमा समाप्त हो रही थी। जब मुझे कुछ समय मिलता है तो मैं एक और उपहार दूंगा। –

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