2015-06-01 11 views
51

एक typeclass जहां उदाहरण चयन किया जाता वापसी प्रकार पर आधारित होना चाहिए देखते हुए:अप्रत्याशित निहित संकल्प वापसी प्रकार से अनुमान पर आधारित

case class Monoid[A](m0: A) // We only care about the zero here 
implicit def s[T] : Monoid[Set[T]] = Monoid(Set.empty[T]) 
implicit def l[T] : Monoid[List[T]] = Monoid(List.empty[T]) 
def mzero[A](implicit m: Monoid[A]) : A = m.m0 

क्यों स्काला (2.11.6) असफल उचित उदाहरण को हल करने देता:

scala> mzero : List[Int] 
<console>:24: error: ambiguous implicit values: 
both method s of type [T]=> Monoid[Set[T]] 
and method l of type [T]=> Monoid[List[T]] 
match expected type Monoid[A] 
       mzero : List[Int] 
      ^

जब यह जब परोक्ष समारोह का उपयोग कर वापसी प्रकार के आधार पर एक अंतर्निहित खोजने कोई समस्या नहीं है (हम इसे यहाँ मैं के रूप में फिर से परिभाषित वर्णन करने के लिए कैसे रों imilar यह)

def i[A](implicit a : A) : A = a 
scala> i : Monoid[List[Int]] 
res18: Monoid[List[Int]] = Monoid(List()) 

Monoid[A], बजाय Monoid[List[Int]] त्रुटि संदेश में puzzling है mzero है।

मैं इस समस्या से परिचित होने के लिए कई स्केलज योगदानकर्ता मानूंगा क्योंकि ऐसा लगता है कि स्केल में टाइपक्लास की सुविधा सीमित है।

संपादित करें: मैं बिना किसी प्रकार के अनुमान के बिना काम कर रहा हूं। अन्यथा मैं समझना चाहता हूं कि यह क्यों संभव नहीं है। यदि इस सीमा को स्कैला मुद्दे के रूप में दस्तावेज किया गया है, तो मुझे यह नहीं मिला।

+4

स्केल की अपेक्षित रिटर्न प्रकारों का उपयोग करने की क्षमता की सीमाएं, जब पैरामीटर शामिल होते हैं तो टाइप पैरामीटर की पहचान करने के लिए अविश्वसनीय रूप से भ्रमित होते हैं, इसलिए हर कोई सिर्फ 'मेज़रो [सूची [Int]] लिखता है। –

+2

कुछ कामकाज के रूप में आप 'mzero' को 'def mzero [ए] के रूप में परिभाषित करके दूर हो सकते हैं (अंतर्निहित एम: मोनोइड [_ <: ए]): ए = एम.एम 0'। ट्रैविस ब्राउन ने उल्लेख किया है कि अगर मैं व्यक्तिगत रूप से 'mzero [सूची [int]] के साथ जाऊंगा। –

+0

प्रभावशाली और आश्चर्यजनक। धन्यवाद! कोई स्पष्टीकरण? ऐसा लगता है कि इस प्रकार को आराम और कम मैच मिल रहा है! –

उत्तर

1

1) इस प्रकार के रूप में अपने कोड को फिर से लिखने के बाद: क्यों कि इतने से काम करता है

case class Monoid[A](m0: A) // We only care about the zero here 
implicit def s[T] : Monoid[Set[T]] = Monoid(Set.empty[T]) 
implicit def l[T] : Monoid[List[T]] = Monoid(List.empty[T]) 
def mzero[A]()(implicit m: Monoid[A]) : A = m.m0 

val zero = mzero[List[Int]]() 
val zero2: List[Int] = mzero() 

तो स्पष्ट रूप से हो जाता है।

2) आपको def mzero[A]()(implicit m: Monoid[_ <: A]) : A = m.m0 के रूप में mzero सेट करने के बाद, आपने अस्तित्व प्रकार को हल करने के लिए अतिरिक्त प्रकार अनुमान लगाया। कंपाइलर को आवश्यक प्रकार के प्रकार से वास्तविक प्रकार मिला। यदि आप चाहें तो def mzero[A <: B, B]()(implicit m: Monoid[A]) : A = m.m0 के साथ इसे देख सकते हैं।

3) बेशक यह व्यवहार केवल कंपाइलर की सूक्ष्मता है और मुझे नहीं लगता कि ऐसे आंशिक मामलों को वास्तव में गहरी समझ की आवश्यकता है।

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