복붙노트

[SCALA] 스칼라에서 FORALL

SCALA

스칼라에서 FORALL

하스켈에서, 아래와 같이, 그것은 그들에 특정 상황에 맞는 범위와 유형이 유형 목록의 값을 저장하는 것이 가능하다 :

data ShowBox = forall s. Show s => ShowBox s

heteroList :: [ShowBox]
heteroList = [ShowBox (), ShowBox 5, ShowBox True]

어떻게 바람직하게는 하위 유형하지 않고, 스칼라에서 동일한을 달성 할 수 있습니까?

해결법

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

    1.@Michael 콜이 주석으로 하스켈 FORALL의 사용은 존재 형태이고 정확히 forSome 구조체 또는 와일드 카드를 사용하여 스칼라 replicted 수있다. 즉, @ 패러다임의 대답은 크게 올바른지.

    @Michael 콜이 주석으로 하스켈 FORALL의 사용은 존재 형태이고 정확히 forSome 구조체 또는 와일드 카드를 사용하여 스칼라 replicted 수있다. 즉, @ 패러다임의 대답은 크게 올바른지.

    그럼에도 불구하고 그 쇼박스 유형의 인스턴스는 정확한 기본 유형이 존재 적 밖으로 정량화 된 경우에도 목록 요소에 사용하기에 사용할 수 있도록하는 방식으로 해당 표시 유형 클래스 인스턴스를 캡처 할 수있는 하스켈 원본이 상대적으로없는 뭔가가있다 . @ 패러다임의 대답에 귀하의 의견은 다음과 같은 하스켈에 뭔가 상당을 쓸 수 있도록 할 것을 제안

    data ShowBox = forall s. Show s => ShowBox s
    
    heteroList :: [ShowBox]
    heteroList = [ShowBox (), ShowBox 5, ShowBox True]
    
    useShowBox :: ShowBox -> String
    useShowBox (ShowBox s) = show s
    
    -- Then in ghci ...
    
    *Main> map useShowBox heteroList
    ["()","5","True"]
    

    @Kim Stebel의 대답 쇼 하위 유형을 이용하여 객체 지향 언어에서 그 일을의 표준 방법입니다. 다른 일들이 스칼라에 갈 수있는 올바른 방법이다 즉, 동일한 것. 난 당신이 알고 확신과 하위 유형 피하고 스칼라에서 하스켈의 타입 클래스 기반의 접근 방식을 복제하고자하는 좋은 이유가있다. 여기 간다 ...

    단위, 지능 및 BOOL에 대한 표시 유형 클래스 인스턴스 위의 하스켈의 useShowBox 기능의 구현에 사용할 수 있습니다. 우리가 직접 스칼라로이 번역하려고하면 우리는 같은 것을 얻을 것이다

    trait Show[T] { def show(t : T) : String }
    
    // Show instance for Unit
    implicit object ShowUnit extends Show[Unit] {
      def show(u : Unit) : String = u.toString
    }
    
    // Show instance for Int
    implicit object ShowInt extends Show[Int] {
      def show(i : Int) : String = i.toString
    }
    
    // Show instance for Boolean
    implicit object ShowBoolean extends Show[Boolean] {
      def show(b : Boolean) : String = b.toString
    }
    
    case class ShowBox[T: Show](t:T)
    
    def useShowBox[T](sb : ShowBox[T]) = sb match {
      case ShowBox(t) => implicitly[Show[T]].show(t)
      // error here      ^^^^^^^^^^^^^^^^^^^
    } 
    
    val heteroList: List[ShowBox[_]] = List(ShowBox(()), ShowBox(5), ShowBox(true))
    
    heteroList map useShowBox
    

    이것은 다음과 같이 useShowBox에서 컴파일에 실패,

    <console>:14: error: could not find implicit value for parameter e: Show[T]
             case ShowBox(t) => implicitly[Show[T]].show(t)
                                          ^
    

    여기서 문제는 하스켈의 경우와는 달리, 표시 형식의 클래스 인스턴스가 useShowBox 함수의 몸에 쇼박스 인수에서 전파되지, 따라서 사용할 수 없습니다되어 있다는 점이다. 우리가 useShowBox 기능에 바인딩 추가 컨텍스트를 추가하여 그 문제를 해결하려고하면,

    def useShowBox[T : Show](sb : ShowBox[T]) = sb match {
      case ShowBox(t) => implicitly[Show[T]].show(t) // Now compiles ...
    } 
    

    useShowBox 내에서이 수정 문제를,하지만 지금 우리는 우리의 존재 적 정량화 목록에지도와 함께 사용할 수 없습니다,

    scala> heteroList map useShowBox
    <console>:21: error: could not find implicit value for evidence parameter
                         of type Show[T]
                  heteroList map useShowBox
                                 ^
    

    useShowBox이지도 함수에 인수로 제공 될 때 우리는 우리가 그 시점에서이 유형의 정보를 기반으로 표시 인스턴스를 선택해야하기 때문이다. 분명히이 목록의 모든 요소에 대한 작업을하고 이것이 우리가 상관 후있을 것이다에 대한 표시 인스턴스를 정의했다면 (컴파일에 실패하지만, 그래서 우리가있어 게 아니에요 것 하나 개 쇼 인스턴스가없는 후 여기에 ... 우리는) ​​각 목록 요소의 가장 구체적인 유형에 따라 유형 클래스의 인스턴스를 선택합니다.

    이 하스켈에서하는 것과 같은 방식으로 작업이를 얻으려면, 우리는 명시 적으로 useShowBox의 신체 내에서 표시 인스턴스를 전달해야합니다. 즉, 다음과 같이 갈 수도

    case class ShowBox[T](t:T)(implicit val showInst : Show[T])
    
    val heteroList: List[ShowBox[_]] = List(ShowBox(()), ShowBox(5), ShowBox(true))
    
    def useShowBox(sb : ShowBox[_]) = sb match {
      case sb@ShowBox(t) => sb.showInst.show(t)
    }
    

    다음 REPL에서,

    scala> heteroList map useShowBox
    res7: List[String] = List((), 5, true)
    

    우리는 우리가 포함 된 값에 대한 표시 인스턴스에 대한 명시 적 이름 (showInst)을 가질 수 있도록 쇼박스에 바인딩 컨텍스트를 desugared 적이 있습니다. 그런 다음 useShowBox의 몸에서 우리는 명시 적으로 적용 할 수 있습니다. 또한 패턴 일치는 우리가 단지 함수의 본문에 일단 실존 형식을 열 수 있도록하는 것이 필수적입니다 있습니다.

    명백해야한다,이 훨씬 더 동등한 하스켈보다 vebose이며, 특별히 다른 매우 좋은 이유가 없다면 난 강력 스칼라의 하위 유형 기반 솔루션을 사용하는 것이 좋습니다 것입니다.

    편집하다

    주석에서 지적 된 바와 같이, 스칼라 쇼박스의 정의는 상기 하스켈 원래 존재하지 않는 표시 형식의 파라미터를 갖는다. 나는 우리가 사용하는 추상적 인 유형을 해결할 수있는 방법을 볼 사실은 꽤 유익 생각합니다.

    먼저 우리는 추상 형식의 멤버 형식 매개 변수를 교체하고 추상적 인 발스와 생성자의 매개 변수를 교체

    trait ShowBox {
      type T
      val t : T
      val showInst : Show[T]
    }
    

    우리는 지금, 사례 클래스 달리 무료로 우리에게 줄 것이라는 팩토리 메소드를 추가해야

    object ShowBox {
      def apply[T0 : Show](t0 : T0) = new ShowBox {
        type T = T0
        val t = t0
        val showInst = implicitly[Show[T]]
      } 
    }
    

    우리는 지금 우리가 이전에 쇼박스 [_]를 사용하는 곳 일반 쇼박스을 사용할 수 있습니다 ... 추상 유형의 멤버가 지금 우리의 존재 한정사의 역할을하고있다,

    val heteroList: List[ShowBox] = List(ShowBox(()), ShowBox(5), ShowBox(true))
    
    def useShowBox(sb : ShowBox) = {
      import sb._
      showInst.show(t)
    }
    
    heteroList map useShowBox
    

    (그것의 가치는 스칼라에서 명시 적 포섬의 도입과 와일드 카드로 그 이전에 이것은 당신이 존재 유형을 나타내는 것입니다 방법을 정확하게했다 지적.)

    원래 하스켈에서와 같이 우리는 지금 정확히 같은 장소에 존재 있습니다. 나는 이것이 당신이 스칼라에서 얻을 수있는 충실한 연주에 가까운 생각합니다.

  2. ==============================

    2.당신이 준 쇼박스의 예는 실존 유형을 포함한다. 나는 유형 구별하기 위해 SB에 쇼박스 데이터 생성자의 이름을 변경하고 있습니다 :

    당신이 준 쇼박스의 예는 실존 유형을 포함한다. 나는 유형 구별하기 위해 SB에 쇼박스 데이터 생성자의 이름을 변경하고 있습니다 :

    data ShowBox = forall s. Show s => SB s
    

    우리는의는 "존재"라고하지만, 여기에 FORALL은 보편적 인 정량하고있는 SB 데이터 생성자에 관한 것이다. 우리가 켜져 명시 적 FORALL와 SB 생성자의 종류를 요청하는 경우이 훨씬 명확하게 :

    SB :: forall s. Show s => s -> ShowBox
    

    즉, 쇼박스 실제로 세 가지로 구성되어 있습니다 :

    유형 (S)가 구성 쇼박스의 일부가되므로, 그것은 실존 정량화된다. 하스켈이 존재 정량 구문을 지원하는 경우, 우리는 타입 별칭으로 쇼박스를 작성할 수 :

    type ShowBox = exists s. Show s => s
    

    스칼라는 존재 정량의이 종류를 지원하지 않습니다와 마일의 대답은 위의 바로 그 세 가지로 구성 특성을 사용하여 세부 사항을 제공합니다. 이 "스칼라의 FORALL"에 대한 질문이기 때문에 그러나, 하스켈이하는 것처럼의 정확히 그것을 할 수 있습니다.

    스칼라의 데이터 생성자는 명시 적으로 FORALL로 정량화 할 수 없습니다. 그러나, 모듈의 모든 방법 일 수있다. 그래서 당신은 효과적으로 보편적 인 정량화와 같은 유형의 생성자 다형성을 사용할 수 있습니다. 예:

    trait Forall[F[_]] {
      def apply[A]: F[A]
    }
    

    어떤 주어진 F 스칼라 형 FORALL [F]를하는 FORALL 하스켈 타입 후 동일하다. F의가.

    우리는 형식 인수에 제약 조건을 추가하려면이 기술을 사용할 수 있습니다.

    trait SuchThat[F[_], G[_]] {
      def apply[A:G]: F[A]
    }
    

    유형 F SuchThat G의 값은 FORALL 하스켈 타입의 값과 같다. G A =>은 F. 만약 존재한다면 G [A]의 예는 암시 스칼라에 의해 조회된다.

    이제, 우리는 당신의 쇼박스를 인코딩하려면이 옵션을 사용할 수 있습니다 ...

    import scalaz._; import Scalaz._ // to get the Show typeclass and instances
    
    type ShowUnbox[A] = ({type f[S] = S => A})#f SuchThat Show
    
    sealed trait ShowBox {
      def apply[B](f: ShowUnbox[B]): B  
    }
    
    object ShowBox {
      def apply[S: Show](s: => S): ShowBox = new ShowBox {
        def apply[B](f: ShowUnbox[B]) = f[S].apply(s)
      }
      def unapply(b: ShowBox): Option[String] =
        b(new ShowUnbox[Option[String]] {
          def apply[S:Show] = s => some(s.shows)
      })
    }
    
    val heteroList: List[ShowBox] = List(ShowBox(()), ShowBox(5), ShowBox(true))
    

    ShowBox.apply 방법은 보편적으로 정량 데이터 생성자이다. 당신은 그냥 하스켈 버전과 같은 타입 S, 쇼의 인스턴스 [S], 및 타입 S의 값을 취하는 것을 볼 수 있습니다.

    다음은 사용 예는 다음과 같습니다

    scala> heteroList map { case ShowBox(x) => x }
    res6: List[String] = List((), 5, true)
    

    스칼라에서 더 직접 인코딩이 경우 클래스를 사용할 수 있습니다 :

    sealed trait ShowBox
    case class SB[S:Show](s: S) extends ShowBox {
      override def toString = Show[S].shows(s)
    }
    

    그때:

    scala> val heteroList = List(ShowBox(()), ShowBox(5), ShowBox(true))
    heteroList: List[ShowBox] = List((), 5, true)
    

    이 경우, 목록 [쇼박스는] 목록 [문자열] 기본적으로 동일하지만 좀 더 흥미로운 무언가를 얻기 위해 표시 이외의 특성과이 기술을 사용할 수 있습니다.

    이 모든 Scalaz에서 표시 typeclass을 사용하고 있습니다.

  3. ==============================

    3.나는 스칼라 하스켈에서 1 대 1 번역 여기에 가능하다고 생각하지 않습니다. 그런데 왜 당신은 하위 유형을 사용하지 않으려는? 당신이 사용에 (int와 같은) 원하는 종류의 쇼 방법이 부족한 경우에도 암시 적 변환을 통해이를 추가 할 수 있습니다.

    나는 스칼라 하스켈에서 1 대 1 번역 여기에 가능하다고 생각하지 않습니다. 그런데 왜 당신은 하위 유형을 사용하지 않으려는? 당신이 사용에 (int와 같은) 원하는 종류의 쇼 방법이 부족한 경우에도 암시 적 변환을 통해이를 추가 할 수 있습니다.

    scala> trait Showable { def show:String }
    defined trait Showable
    
    scala> implicit def showableInt(i:Int) = new Showable{ def show = i.toString }
    showableInt: (i: Int)java.lang.Object with Showable
    
    scala> val l:List[Showable] = 1::Nil
    l: List[Showable] = List($anon$1@179c0a7)
    
    scala> l.map(_.show)
    res0: List[String] = List(1)
    
  4. ==============================

    4.(편집 : 응답 코멘트에, 쇼 방법을 추가.)

    (편집 : 응답 코멘트에, 쇼 방법을 추가.)

    난 당신이 같은 컨텍스트 경계를 가지는 암시 적 방법을 사용하여 얻을 수 있다고 생각합니다 :

    trait Show[T] {
      def apply(t:T): String
    }
    implicit object ShowInt extends Show[Int] {
      def apply(t:Int) = "Int("+t+")"
    }
    implicit object ShowBoolean extends Show[Boolean] {
      def apply(t:Boolean) = "Boolean("+t+")"
    }
    
    case class ShowBox[T: Show](t:T) {
      def show = implicitly[Show[T]].apply(t)
    }
    
    implicit def box[T: Show]( t: T ) =
      new ShowBox(t)
    
    val lst: List[ShowBox[_]] = List( 2, true )
    
    println( lst ) // => List(ShowBox(2), ShowBox(true))
    
    val lst2 = lst.map( _.show )
    
    println( lst2 ) // => List(Int(2), Boolean(true))
    
  5. ==============================

    5.왜 :

    왜 :

    trait ShowBox {
        def show: String
    }
    
    object ShowBox {
        def apply[s](x: s)(implicit i: Show[s]): ShowBox = new ShowBox {
            override def show: String = i.show(x)
        }
    }
    

    당국 '대답 제안으로, 나는 종종 스칼라은 매우 간단 하나에 "하스켈 타입의 몬스터"를 번역 할 수 있음을 놀라게하고있다.

  6. from https://stackoverflow.com/questions/7213676/forall-in-scala by cc-by-sa and MIT license