복붙노트

[SCALA] 형의 클래스 인스턴스를 보장하기 위해 "부정적인"상황에 맞는 경계를 사용하면 범위에서 결석

SCALA

형의 클래스 인스턴스를 보장하기 위해 "부정적인"상황에 맞는 경계를 사용하면 범위에서 결석

TL; DR : 어떻게 아래 만들어 코드와 같은 일을 수행합니다

def notFunctor[M[_] : Not[Functor]](m: M[_]) = s"$m is not a functor"

'[펑 터는]되지 않음', 여기에 일부를 만들어지고. 나는 그것이 제공하는 'm'이 펑터하지 않을 때 성공하고, 그렇지 않으면 컴파일러를 실패합니다.

해결 : 질문의 나머지를 건너 뛰고 아래의 답변을 바로 가서.

내가 달성 노력하고있어 대략 "부정적인 증거", 말하기,이다.

의사 코드는 지금과 같이 보일 것입니다 :

// type class for obtaining serialization size in bytes.
trait SizeOf[A] { def sizeOf(a: A): Long }

// type class specialized for types whose size may vary between instances
trait VarSizeOf[A] extends SizeOf[A]

// type class specialized for types whose elements share the same size (e.g. Int)
trait FixedSizeOf[A] extends SizeOf[A] {
  def fixedSize: Long
  def sizeOf(a: A) = fixedSize
}

// SizeOf for container with fixed-sized elements and Length (using scalaz.Length)
implicit def fixedSizeOf[T[_] : Length, A : FixedSizeOf] = new VarSizeOf[T[A]] {
  def sizeOf(as: T[A]) = ... // length(as) * sizeOf[A]
}

// SizeOf for container with scalaz.Foldable, and elements with VarSizeOf
implicit def foldSizeOf[T[_] : Foldable, A : SizeOf] = new VarSizeOf[T[A]] {
  def sizeOf(as: T[A]) = ... // foldMap(a => sizeOf(a))
}

그것은 우리에게 컬렉션을 통해 탐색을 절약 할 수 있기 때문에 fixedSizeOf ()는, 적절한 경우 바람직 있음을 유의하십시오.

이 방법은, 단지 길이가 정의 (그러나 접이식되지 않음)되는 컨테이너 유형 및 FixedSizeOf가 정의 요소에 대해, 우리는 향상된 성능을 얻을.

사건의 나머지 부분에서는 컬렉션을 통해 이동 및 개별 크기를 요약.

내 문제는 길이와 접이식 모두가 컨테이너에 대해 정의 된 경우이며, FixedSizeOf은 요소에 대한 정의된다. 이 여기에 매우 일반적인 경우입니다 (예를 들어, :. 목록 [지능]는 모두 정의가).

예:

scala> implicitly[SizeOf[List[Int]]].sizeOf(List(1,2,3))
<console>:24: error: ambiguous implicit values:
 both method foldSizeOf of type [T[_], A](implicit evidence$1: scalaz.Foldable[T], implicit evidence$2: SizeOf[A])VarSizeOf[T[A]]
 and method fixedSizeOf of type [T[_], A](implicit evidence$1: scalaz.Length[T], implicit evidence$2: FixedSizeOf[A])VarSizeOf[T[A]]
 match expected type SizeOf[List[Int]]
              implicitly[SizeOf[List[Int]]].sizeOf(List(1,2,3))

내가하고 싶은 것은 길이 + FixedSizeOf 조합이 적용되지 않는 경우에만 접이식 타입 클래스에 의존 할 수있다.

이를 위해, 나는 VarSizeOf 요소를 받아 foldSizeOf ()의 정의를 변경할 수 있습니다 :

implicit def foldSizeOfVar[T[_] : Foldable, A : VarSizeOf] = // ...

그리고 지금 우리 FixedSizeOf 요소와 정의 된 길이 접이식 컨테이너를 다루고 문제가있는 부분을 작성해야합니다. 나는이 접근하는 방법을 잘 모르겠지만, 의사 코드는 같을 것이다 :

implicit def foldSizeOfFixed[T[_] : Foldable : Not[Length], A : FixedSizeOf] = // ...

'하지 않음 [길이], 분명히, 여기에 만들어 일부를 제공합니다.

내가 알고 있는데 일부 솔루션

1) 낮은 우선 순위 implicits 대한 클래스를 정의와 '객체가 PREDEF LowPriorityImplicits 확장'에 도시 된 바와 같이, 그것을 확장한다. 마지막 암시 (foldSizeOfFixed ()) 상위 클래스에 정의 할 수 있고, 자손 클래스에서 다른 오버라이드 (override) 할 것입니다.

나는 결국 인 SizeOf의 재귀 적 사용을 지원할 수 있도록하고 싶습니다 때문에이 옵션에 관심이 아니에요, 이것은 (내 올바른 여기 이해하는 하위 클래스들에 의존에서 낮은 우선 순위 기본 클래스에서 암시를 방지 할 수 있습니다? 편집 :! 잘못 하위 클래스의 컨텍스트에서 암시 조회 작업이 실행 가능한 솔루션입니다)!

2) 거친 접근 방식은 옵션에 의존이다 TypeClass (예를 들어, : 옵션 [길이 [목록]]. 그 중 몇 난 그냥 암시 하나의 큰 팔자 '를 쓸 수 필수 및 길이와 FixedSizeOf로 추천 접이식 및 인 SizeOf 옵션, 그리고 그들이 사용할 수있는 경우 후자에 의존한다 (출처 : 여기).

아무 관련 타입 클래스 인스턴스가 위치한 수없는 경우에 여기에서 두 가지 문제는 모듈화의 부족 및 런타임 예외 떨어지는 돌아 (이 예는 아마이 솔루션과 함께 작업을 할 수 있지만 항상 가능한 것은 아니다)

편집 : 이것은 내가 선택 implicits으로 얻을 수있었습니다 최고입니다. 그것은 아직 아니다 :

implicit def optionalTypeClass[TC](implicit tc: TC = null) = Option(tc)
type OptionalLength[T[_]] = Option[Length[T]]
type OptionalFixedSizeOf[T[_]] = Option[FixedSizeOf[T]]

implicit def sizeOfContainer[
    T[_] : Foldable : OptionalLength,
    A : SizeOf : OptionalFixedSizeOf]: SizeOf[T[A]] = new SizeOf[T[A]] {
  def sizeOf(as: T[A]) = {

    // optionally calculate using Length + FixedSizeOf is possible
    val fixedLength = for {
      lengthOf <- implicitly[OptionalLength[T]]
      sizeOf <- implicitly[OptionalFixedSizeOf[A]]
    } yield lengthOf.length(as) * sizeOf.fixedSize

    // otherwise fall back to Foldable
    fixedLength.getOrElse { 
      val foldable = implicitly[Foldable[T]]
      val sizeOf = implicitly[SizeOf[A]]
      foldable.foldMap(as)(a => sizeOf.sizeOf(a))
    }
  }
}

여전히 필요하다, 이전부터 fixedSizeOf ()이 충돌을 예외입니다.

어떤 도움이나 관점을 주셔서 감사합니다 :-)

해결법

  1. ==============================

    1.나는 결국 상속을 사용하여 우선 순위를 필요로하지 않는 모호성 기반 솔루션을 사용하여이 문제를 해결했다.

    나는 결국 상속을 사용하여 우선 순위를 필요로하지 않는 모호성 기반 솔루션을 사용하여이 문제를 해결했다.

    다음은이 일반화에서 내 시도이다.

    우리는 네거티브 형 클래스를 구성 할 수 없음 [A] 유형을 사용 :

    import scala.language.higherKinds
    
    trait Not[A]
    
    trait Monoid[_] // or import scalaz._, Scalaz._
    type NotMonoid[A] = Not[Monoid[A]] 
    
    trait Functor[_[_]] // or import scalaz._, Scalaz._
    type NotFunctor[M[_]] = Not[Functor[M]]
    

    ... 다음 상황에 맞는 범위로 사용할 수있다 :

    def foo[T: NotMonoid] = ...
    

    우리는하지 않음 [A]의 모든 유효한 식는 적어도 하나 개의 암시 적 인스턴스를 얻을 것이라는 점을 보장하여 진행합니다.

    implicit def notA[A, TC[_]] = new Not[TC[A]] {}
    

    인스턴스는 'NOTA'라고 - '하지'가있는 경우에만 인스턴스를 찾을 때문에 '하지 않음 [TC [A]]'그 부정적인 유형 클래스를 적용 발견; 'A'는 통상의 방법에 대해 첨부되는 평면 형상의 종류 (예를 들면 int)를 다룬다.

    우리는 지금 원하지 않는 종류의 클래스가 적용되는 경우를 외면하는 모호성을 소개 :

    implicit def notNotA[A : TC, TC[_]] = new Not[TC[A]] {}
    

    우리는 'TC'로 지정 유형 클래스의 인스턴스가 암시 적 범위에 존재하는 유형에 관심이 여기에 제외 이것은 거의 정확하게 'NOTA'과 동일합니다. 인스턴스는 단지 암시 적 존재가 고개를 일치하여 이후, 'notNotA'라는 이름, 그것은 (우리의 목표입니다) 암시 적 검색을 실패 'NOTA'와 함께 모호성을 만듭니다.

    의는 사용 예를 통해 가자. 우리는 위에서 'NotMonoid'네거티브 형 클래스를 사용합니다 :

    implicitly[NotMonoid[java.io.File]] // succeeds
    implicitly[NotMonoid[Int]] // fails
    
    def showIfNotMonoid[A: NotMonoid](a: A) = a.toString
    
    showIfNotMonoid(3) // fails, good!
    showIfNotMonoid(scala.Console) // succeeds for anything that isn't a Monoid
    

    여태까지는 그런대로 잘됐다! 그러나, 유형 M [_]을 형성하고 입력 클래스 [_ [_] TC 위의 방식에 의해 현재 지원되지 않는 형상. 의뿐만 아니라 그들을 위해 implicits를 추가 할 수 있습니다 :

    implicit def notM[M[_], TC[_[_]]] = new Not[TC[M]] {}
    implicit def notNotM[M[_] : TC, TC[_[_]]] = new Not[TC[M]] {}
    
    implicitly[NotFunctor[List]] // fails
    implicitly[NotFunctor[Class]] // succeeds
    

    간단한 충분. 모양을 '적용 취소'에 대한 - Scalaz 여러 종류의 모양을 취급으로 인한 보일러에 대한 해결 방법을 가지고 있습니다. 나는 그것이 마치 마법처럼 TC [_ [_] (예를 들면은 Functor)에 근무하더라도 (예 : 모노 이드와 같은 모양 TC [_]의 형태 클래스) 기본 경우에 그것의 사용을 할 수 없었다 그래서이 답변은 적용되지 않습니다.

    아무도 관심이 있다면, 여기의 모든 것이 하나의 코드에서 필요한 :

    import scala.language.higherKinds
    
    trait Not[A]
    
    object Not {
      implicit def notA[A, TC[_]] = new Not[TC[A]] {}
      implicit def notNotA[A : TC, TC[_]] = new Not[TC[A]] {}
    
      implicit def notM[M[_], TC[_[_]]] = new Not[TC[M]] {}
      implicit def notNotM[M[_] : TC, TC[_[_]]] = new Not[TC[M]] {}
    }
    
    import Not._
    
    type NotNumeric[A] = Not[Numeric[A]]
    implicitly[NotNumeric[String]] // succeeds
    implicitly[NotNumeric[Int]] // fails
    

    나는이 문제에 대한 질문 의사 코드 때문에 (실제 코드)과 같을 것이다 :

    // NotFunctor[M[_]] declared above
    def notFunctor[M[_] : NotFunctor](m: M[_]) = s"$m is not a functor"
    

    업데이트 : 유사 기술은 암시 적 변환에 적용 :

    import scala.language.higherKinds
    
    trait Not[A]
    
    object Not {
      implicit def not[V[_], A](a: A) = new Not[V[A]] {}
      implicit def notNot[V[_], A <% V[A]](a: A) = new Not[V[A]] {}
    }
    

    우리는 지금 (예를 들어) 순서가 그들의 유형을 볼 수없는 경우에만 가치를 인정하는 함수를 정의 할 수 있습니다 :

    def unordered[A <% Not[Ordered[A]]](a: A) = a
    
  2. from https://stackoverflow.com/questions/15962743/using-context-bounds-negatively-to-ensure-type-class-instance-is-absent-from-s by cc-by-sa and MIT license