2015-09-24 11 views
6
[error] test.scala:31: ambiguous implicit values: 
[error] both method taggedQueryParamDecoder in trait ExternalInstances0 of type [A, T](implicit evidence$2: org.http4s.QueryParamDecoder[A])org.http4s.QueryParamDecoder[[email protected]@[A,T]] 
[error] and method iiQueryParamDecoder in trait ExternalInstances1 of type [B](implicit ii: foo.InvariantInstances[B])org.http4s.QueryParamDecoder[B] 
[error] match expected type org.http4s.QueryParamDecoder[[email protected]@[String,foo.tags.Social]] 
[error] implicitly[QueryParamDecoder[String @@ Social]] 
[error]   ^

मैं instances._ आयात करता हूं; instancesExternalInstances1 बढ़ाता है, और ExternalInstances1ExternalInstances0 बढ़ाता है। इस विरासत की वजह से मैं ExternalInstances1 के सदस्यों को अस्पष्टता प्रदान करने के बजाय ExternalInstances0 से अधिक जीतने की उम्मीद करूंगा।प्राथमिकता के बावजूद मुझे "संदिग्ध निहितार्थ" त्रुटि क्यों मिलती है?

यह क्यों हो रहा है, और मैं इसे कैसे ठीक कर सकता हूं? धन्यवाद।

स्रोत http://scastie.org/12233 पर है, नीचे reproduced:

/*** 
scalaVersion := "2.11.7" 

libraryDependencies += "org.http4s" %% "http4s-core" % "0.10.0" 

resolvers ++= Seq(
    "tpolecat" at "http://dl.bintray.com/tpolecat/maven", 
    "Scalaz Bintray Repo" at "http://dl.bintray.com/scalaz/releases", 
    Resolver.sonatypeRepo("releases") 
) 

libraryDependencies += "org.tpolecat" %% "doobie-core" % "0.2.2" 

libraryDependencies += "com.github.alexarchambault" %% "argonaut-shapeless_6.1" % "0.3.1" 
*/ 

import java.time.LocalDate 

import argonaut._, Argonaut._ 
import doobie.imports._ 
import doobie.util.composite.Composite 
import tags._ 
import instances._ 
import org.http4s._ 

import scala.reflect.runtime.universe.TypeTag 
import scalaz._ 

object Main extends App { 
    implicitly[QueryParamDecoder[String @@ Social]] 
    println("ok") 
} 

object tags { 
    trait Social; val Social = Tag.of[Social] 
} 

object instances extends ExternalInstances1 { 
    implicit val ssn: InvariantInstances[String @@ Social] = 
    InvariantInstances { (raw: String) ⇒ 
     val digitsOnly = raw.filter(_.isDigit) 
     require(digitsOnly.length == 9) 
     Social(digitsOnly) 
    }(Social.unwrap) 
} 

trait ExternalInstances1 extends ExternalInstances0 { 
    implicit def iiCodecJson[B](implicit ii: InvariantInstances[B]): CodecJson[B] = ii.codecJson 
    implicit def iiEncodeJson[B](implicit ii: InvariantInstances[B]): EncodeJson[B] = ii.encodeJson 
    implicit def iiDecodeJson[B](implicit ii: InvariantInstances[B]): DecodeJson[B] = ii.decodeJson 
    implicit def iiMeta[B](implicit ii: InvariantInstances[B]): Meta[B] = ii.meta 
    implicit def iiQueryParamEncoder[B](implicit ii: InvariantInstances[B]): QueryParamEncoder[B] = ii.queryParamEncoder 
    implicit def iiQueryParamDecoder[B](implicit ii: InvariantInstances[B]): QueryParamDecoder[B] = ii.queryParamDecoder 
} 

trait ExternalInstances0 { 
    implicit def taggedEncodeJson[A, T](implicit A: EncodeJson[A]): EncodeJson[A @@ T] = 
    A.contramap(Tag.of[T].unwrap) 

    implicit def taggedDecodeJson[A, T](implicit A: DecodeJson[A]): DecodeJson[A @@ T] = 
    A.map(Tag.of[T].apply) 

    implicit def taggedComposite[A: Composite, T]: Composite[A @@ T] = 
    Composite[A].xmap(a => Tag[A, T](a), Tag.unwrap(_)) 

    implicit def taggedQueryParamDecoder[A: QueryParamDecoder, T]: QueryParamDecoder[A @@ T] = 
    QueryParamDecoder.decodeBy(Tag.of[T](_: A)) 

} 

trait InvariantInstances[B] { 
    def codecJson: CodecJson[B] 
    def decodeJson: DecodeJson[B] 
    def encodeJson: EncodeJson[B] 
    def meta: Meta[B] 
    def queryParamEncoder: QueryParamEncoder[B] 
    def queryParamDecoder: QueryParamDecoder[B] 
} 

object InvariantInstances { 
    def apply[A: EncodeJson: DecodeJson: Meta: QueryParamDecoder: QueryParamEncoder, B: TypeTag](f: A ⇒ B)(g: B ⇒ A) = 
    new InvariantInstances[B] { 
     def codecJson: CodecJson[B] = 
     CodecJson.derived[B](encodeJson, decodeJson) 

     def decodeJson: DecodeJson[B] = 
     implicitly[DecodeJson[A]].map(f) 

     def encodeJson: EncodeJson[B] = 
     implicitly[EncodeJson[A]].contramap(g) 

     def meta: Meta[B] = 
     implicitly[Meta[A]].xmap(f, g) 

     def queryParamDecoder: QueryParamDecoder[B] = 
     CovariantInstances.queryParamDecoder(f) 

     def queryParamEncoder: QueryParamEncoder[B] = 
     ContravariantInstances.queryParamEncoder(g) 
    } 
} 

object CovariantInstances { 
    def queryParamDecoder[A, B](f: A ⇒ B)(implicit A: QueryParamDecoder[A], 
             B: reflect.runtime.universe.TypeTag[B]): QueryParamDecoder[B] = 
    new QueryParamDecoder[B] { 
     import scalaz.Validation.FlatMap._ // suppress deprecation warning 

     def decode(value: QueryParameterValue): ValidationNel[ParseFailure, B] = 
     A.decode(value).flatMap(
      a ⇒ Validation.fromTryCatchNonFatal(f(a)).leftMap(t => 
      ParseFailure(s"Query decoding ${B.tpe.typeSymbol} failed", t.getMessage) 
     ).toValidationNel 
     ) 
    } 
} 

object ContravariantInstances { 
    def queryParamEncoder[A, B](g: B ⇒ A)(implicit A: QueryParamEncoder[A]): QueryParamEncoder[B] = 
    new QueryParamEncoder[B] { 
     def encode(value: B): QueryParameterValue = A.encode(g(value)) 
    } 
} 
+0

आप 'implicits' को प्राथमिकता नहीं दे सकते। विरासत के माध्यम से आप केवल प्रारंभिक आदेश को प्रभावित कर सकते हैं। यदि आप 'बाहरीInstances1' से * जीत * के अंतर्निहित चाहते हैं, तो आपको 'बाहरीInstances0' के' implicits 'को ओवरराइड करना चाहिए। –

+3

@ सस्चा कोलबर्ग: हाँ आप कर सकते हैं, और यह एक आम स्केल मुहावरे है। उदाहरण के द्वारा देखें: http://stackoverflow.com/questions/1886953/is-there-a-way-to-control-which-implicit-conversion-will-be-the-default-used –

+1

एचएम, मेरा बुरा, didn यह नहीं पता। खैर, जैसा कि आपके दो निहित रूपांतरणों में थोड़ा अलग हस्ताक्षर हैं, मुझे लगता है कि विरासत से कम प्राथमिकता वाले रूपांतरण के हस्ताक्षर के लिए बेहतर स्कोर हो सकता है और एक अजीब दुर्घटना के कारण वे दोनों एक ही स्कोर के साथ समाप्त हो जाते हैं। लेकिन मैं इसे डीबग करने वाला व्यक्ति नहीं बनना चाहता;) –

उत्तर

3

साशा Kolberg की टिप्पणी और http://eed3si9n.com/revisiting-implicits-without-import-tax के आधार पर, मुझे लगता है मैं ExternalInstances0 (+1 अंक) में एक "अधिक विशिष्ट" परिभाषा है लगता है और एक "उच्च प्राथमिकता "ExternalInstances1 (+1 बिंदु) में परिभाषा एक टाई और अस्पष्टता की ओर अग्रसर है।

मेरा कामकाज टाई तोड़ने के लिए ExternalInstances1 (+2 अंक?) में "अधिक विशिष्ट, उच्च प्राथमिकता" परिभाषा को जोड़ना था, भले ही यह कोड को डुप्लिकेट कर रहा हो जो मूल रूप से बॉयलरप्लेट के साथ शुरू हो।

मुझे एक बेहतर समाधान पता होना अच्छा लगेगा। धन्यवाद!

trait ExternalInstances1 extends ExternalInstances0 { 
    implicit def iiCodecJson[B](implicit ii: InvariantInstances[B]): CodecJson[B] = ii.codecJson 
    implicit def iiEncodeJson[B](implicit ii: InvariantInstances[B]): EncodeJson[B] = ii.encodeJson 
    implicit def iiDecodeJson[B](implicit ii: InvariantInstances[B]): DecodeJson[B] = ii.decodeJson 
    implicit def iiMeta[B](implicit ii: InvariantInstances[B]): Meta[B] = ii.meta 
    implicit def iiQueryParamEncoder[B](implicit ii: InvariantInstances[B]): QueryParamEncoder[B] = ii.queryParamEncoder 
    implicit def iiQueryParamDecoder[B](implicit ii: InvariantInstances[B]): QueryParamDecoder[B] = ii.queryParamDecoder 

    implicit def iiCodecJsonT[B,T](implicit ii: InvariantInstances[B @@ T]): CodecJson[B @@ T] = ii.codecJson 
    implicit def iiEncodeJsonT[B,T](implicit ii: InvariantInstances[B @@ T]): EncodeJson[B @@ T] = ii.encodeJson 
    implicit def iiDecodeJsonT[B,T](implicit ii: InvariantInstances[B @@ T]): DecodeJson[B @@ T] = ii.decodeJson 
    implicit def iiMetaT[B,T](implicit ii: InvariantInstances[B @@ T]): Meta[B @@ T] = ii.meta 
    implicit def iiQueryParamEncoderT[B,T](implicit ii: InvariantInstances[B @@ T]): QueryParamEncoder[B @@ T] = ii.queryParamEncoder 
    implicit def iiQueryParamDecoderT[B,T](implicit ii: InvariantInstances[B @@ T]): QueryParamDecoder[B @@ T] = ii.queryParamDecoder 
} 
+0

क्या आप सिर्फ 'बाहरी इंस्टेंस 0' और 'बाहरी निवेश 1' को स्वैप नहीं कर सकते? ठीक काम करने लगता है (दोनों 'स्पष्ट रूप से [QueryParamDecoder [स्ट्रिंग @@ सोशल]] निहित [QueryParamDecoder [स्ट्रिंग]]' सही ढंग से संकलित करें। हालांकि मैं केवल इतना कह सकता हूं कि यह ठीक से संकलित करता है, न कि यह आप जो अपेक्षा करते हैं वह करता है। –

+0

दाएं, उन्हें स्वैप करना संघर्ष को हल करेगा लेकिन 'बाहरी निवेश 0' को उच्च प्राथमिकता देगा; मैं चाहता हूं कि इसकी प्राथमिकता हो। – arya

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