2017-01-17 9 views
5

मैं उच्च kinded प्रकार में मेरी उंगलियों डुबकी कर रहा हूँ, एक बहुत ही बुनियादी स्काला उदाहरण की खोज:स्काला उच्च kinded प्रकार विचरण

trait Mappable[F[_]] { 
    def map[A, B](fa: F[A])(f: A => B): F[B] 
} 

object Mappable { 
    implicit object MappableOption extends Mappable[Option] { 
    def map[A, B](fa: Option[A])(f: A => B): Option[B] = fa.map(f) 
    } 
    implicit object MappableSeq extends Mappable[Seq] { 
    def map[A, B](fa: Seq[A])(f: A => B): Seq[B] = fa.map(f) 
    } 
} 

def bananaTuple[F[_], T](f: F[T])(implicit F: Mappable[F]): F[(String, T)] = 
    F.map(f)(("banana", _)) 

यह काम करता है:

bananaTuple(Option(42)) // Some((banana,42)) 
bananaTuple(Seq(42)) // List((banana,42)) 

लेकिन इस संकलन नहीं करता है:

bananaTuple(Some(42)) 
bananaTuple(List(42)) 

संकलन त्रुटियां मुझे मिलती हैं:

could not find implicit value for parameter F: ch.netzwerg.hkt.HigherKindedTypes.Mappable[Some] bananaTuple(Some(42)) 

not enough arguments for method bananaTuple: (implicit F: ch.netzwerg.hkt.HigherKindedTypes.Mappable[Some])Some[(String, Int)]. Unspecified value parameter F. bananaTuple(Some(42)) 

मैं गेम में भिन्नता कैसे ला सकता हूं?

+0

मैपबल के लिए एफ तर्क invariant है, इसलिए आप इसे भिन्न एनोटेशन के साथ ठीक करने में सक्षम नहीं होंगे। – erdeszt

उत्तर

2

हम कर सकते हैं थोड़ा और parameteric बहुरूपता के साथ इस काम करने के:

object MappableExample { 
    trait Mappable[F[_]] { 
    type Res[_] 
    def map[A, B](f: A => B)(c: F[A]): Res[B] 
    } 

    implicit def seqMappable[C[X] <: Seq[X]] = new Mappable[C] { 
    type Res[X] = Seq[X] 
    override def map[A, B](f:A => B)(c: C[A]): Seq[B] = c.map(f) 
    } 

    implicit def optionMappable[C[X] <: Option[X]]: Mappable[C] = new Mappable[C] { 
    type Res[X] = Option[X] 
    override def map[A, B](f: A => B)(c: C[A]): Option[B] = c.map(f) 
    } 

    def map[A, B, C[_]](xs: C[A])(f: A => B)(implicit mappable: Mappable[C]): mappable.Res[B] = { 
    mappable.map(f)(xs) 
    } 

    def main(args: Array[String]): Unit = { 
    println(map(List(1,2,3))(("banana", _))) 
    println(map(Some(1))(("banana", _))) 
    } 
} 

पैदावार:

List((banana,1), (banana,2), (banana,3)) 
Some((banana,1)) 

संकलक अब infers काफी बदसूरत है जो SomeMappable[Some]#Res[Int] के रूप में और Mappable[List]#Res[Int]। एक उम्मीद करेगा कि संकलक वास्तव में Mappable विशेषता पर किसी भी सह/contravariance की आवश्यकता के बिना सही प्रकार का अनुमान लगाने में सक्षम होने की उम्मीद करेगा, जिसे हम एक परिवर्तनीय स्थिति में उपयोग करने के बाद से नहीं कर सकते हैं।

+0

अच्छा विचार। बीटीडब्ल्यू टाइपो अलर्ट - आप नामों का उपयोग कर रहे हैं Res and Out एक दूसरे के रूप में। – slouc

+0

@slouc Whoops। फिक्स्ड। :) –

+0

यह केवल बदसूरत प्रकारों का उल्लंघन करता है क्योंकि आपने निर्दिष्ट किया है 'मैप्टेबल [सी] {टाइप रेज़ [एक्स] = विकल्प [एक्स]} 'के बजाय' मैपबल [सी]' के रूप में वापसी प्रकार '। आप [Aux पैटर्न] के साथ थोड़ा सा साफ़ कर सकते हैं (http: // stackoverflow .com/प्रश्न/38541271/डब्ल्यू हैट-करता--aux-पैटर्न को पूरा-इन-स्केला)। –

1

सबटाइप पॉलिमॉर्फिज्म हमें किसी विधि या उसके उपप्रकारों के किसी विधि को मानने की अनुमति देता है। यदि कोई विधि फल के प्रकार का मूल्य लेती है, तो हम अंदर एक ऐप्पल भी पास कर सकते हैं (एक सेब एक फल है)। इसलिए यदि आप एक मैप्पेबल पास करने में सक्षम होना चाहते हैं। मैपनेबल ऑप्शन को अपने केले टुपल विधि में, आपको मैप्टेबलऑप्शन को मैप्टेबलसोम का एक उप प्रकार बनाना होगा (क्योंकि केलाटाउपल के आपके पहले पैरामीटर के प्रकार को अंतर्निहित निर्देश दिया जाता है)। इसका मतलब है कि आप अपने मैपेबल contravariant (यदि Some <: Option, तो Mappable[Some] >: Mappable[Option]) चाहते हैं।

लेकिन तुम एफ में Mappable[F[_]] contravariant क्योंकि एफ map की covariant स्थान पर दिखाई देता है (एक समारोह पैरामीटर के रूप में) नहीं हो सकता। ध्यान दें कि एफ map (वापसी मूल्य के रूप में) की contravariant स्थिति में भी प्रकट होता है।

यदि आप Mappable[F[_]] एफ में contravariant बनाने के लिए प्रबंधन करते हैं, तो यह काम करना चाहिए, लेकिन मुझे यकीन नहीं है कि इसे contravariant समझ में आता है। यही है, अगर आप उप प्रकार के रिश्ते जैसे उदा। Apple <: Fruit परिणामस्वरूप Mappable[Apple] >: Mappable[Fruit] (यह संकलित नहीं होगा क्योंकि ऐप्पल और फल कन्स्ट्रक्टर टाइप नहीं कर रहे हैं, लेकिन मैं यहां एक बिंदु बनाने के लिए सरल प्रकार का उपयोग कर रहा हूं)।

अपने प्रकार में एक प्रकार का contravariant बनाना और कॉन्व्रैरिएंट प्रकार में दिखाई देने वाले contravariant प्रकार की समस्या को हल करना एक आम समस्या है और शायद यह बेहतर है अगर आप इसे कहीं और खोजते हैं (here एक उदाहरण है)। मुझे अभी भी लगता है कि प्रत्येक प्रकार के लिए एक अंतर्निहित वस्तु प्रदान करना बेहतर है, जिसका उपयोग आप अलग-अलग अंतर्निहित वस्तुओं को प्रदान करना चाहते हैं। Seq और List

+0

आपकी व्याख्या के लिए धन्यवाद, आपका कोड पूरी तरह से काम करता है। हालांकि, अगर मैं अपने उदाहरण को अपने उदाहरण (जहां एचकेटी शामिल है) पर पोर्ट करने का प्रयास करता हूं, तो यह अभी भी काम नहीं करता है: 'केले टुपल (कुछ (42)) (मैपेबल। मैपेबलऑप्शन)' संकलित नहीं करता है "[...] विशेषता मैप्टेबल प्रकार एफ में invariant है। आप इसके बजाय एफ के रूप में परिभाषित करना चाह सकते हैं।"_ क्या आप इसे उदाहरण में दिखाए गए प्रकारों के साथ समझाएंगे? – netzwerg

+0

ठीक है मेरे प्रश्न को संपादित किया गया है, क्योंकि मेरा मूल उत्तर थोड़ा सा विषय है (आपके पास फू और फू 2 जैसी कक्षाएं नहीं हैं, लेकिन केवल एक मैपबल) – slouc

+0

स्पष्टीकरण के लिए धन्यवाद। किसी भी तरह, उत्परिवर्तन कोड में केवल बुरा नहीं है, बल्कि जब एसओ उत्तरों की बात आती है। अब जब आपने अपना जवाब संपादित किया है, तो मेरी टिप्पणी ऊपर पूर्ण बकवास की तरह पढ़ती है - कभी नहीं ;-) – netzwerg

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