Подтвердить что ты не робот

Что такое "при" в бесформенном (scala)?

Я видел объект (возможно, функцию), называемый "на", посыпанный бесформенным источником и кодом, который использует бесформенность. В частности, он используется в ответе на этот другой вопрос. Вот фрагмент кода:

object iterateOverHList extends Poly1 {
  implicit def iterable[T, L[T] <: Iterable[T]] = at[L[T]](_.iterator)
}

У меня было некоторое представление, что оно связано с методом apply типа ~ > . Что конкретно делает "at", и где оно определено?

4b9b3361

Ответ 1

Определение PolyN#at

at - общий способ работы с Poly.

~> с apply является особым случаем Poly1. apply здесь используется для определения неявного метода с помощью at:

implicit def caseUniv[T] = at[F[T]](apply(_))

Метод at определяется в PolyN (например, в Poly1) следующим образом:

trait PolyN extends Poly { outer =>
  type Case[T1, T2, ..., TN] = poly.Case[this.type, T1 :: T2 :: ... :: TN :: HNil]
  object Case {
    type Aux[T1, T2, ..., TN, Result0] = poly.Case[outer.type, T1 :: T2 :: ... :: TN :: HNil] { type Result = Result0 }
  }

  class CaseBuilder[T1, T2, ..., TN] {
    def apply[Res](fn: (T1, T2, ..., TN) => Res) = new Case[T1, T2, ..., TN] {
      type Result = Res
      val value = (l: T1 :: T2 :: ... :: TN :: HNil) => l match {
        case a1 :: a2 :: ... :: aN :: HNil => fn(a1, a2, ..., aN)
      }
    }
  }

  def at[T1, T2, ..., TN] = new CaseBuilder[T1, T2, ..., TN]
}

В случае Poly1:

trait Poly1 extends Poly { outer =>
  type Case[T1] = poly.Case[this.type, T1 :: HNil]
  object Case {
    type Aux[T1, Result0] = poly.Case[outer.type, T1 :: HNil] { type Result = Result0 }
  }

  class CaseBuilder[T1] {
    def apply[Res](fn: (T1) => Res) = new Case[T1] {
      type Result = Res
      val value = (l: T1) => l match {
        case a1 :: HNil => fn(a1)
      }
    }
  }

  def at[T1] = new CaseBuilder[T1]
}

Итак, at[Int] создает экземпляр CaseBuilder[Int] и at[Int].apply[String](_.toString) или просто at[Int](_.toString) (синтаксический сахар для вызова метода apply) создает экземпляр poly.Case[this.type, Int :: HNil]{ type Result = String }.

Итак, с помощью implicit def iterable[T, L[T] <: Iterable[T]] = at[L[T]](_.iterator) вы создаете неявный метод для создания poly.Case[this.type, L[T] :: HNil]{ type Result = Iterator[T] }.

Этот неявный метод используется в map (и в некоторых других полиморфных функциях).

Реализация HList#map

map определяется следующим образом:

def map(f : Poly)(implicit mapper : Mapper[f.type, L]) : mapper.Out = mapper(l)

(L - тип HList)

Чтобы создать компилятор Mapper выглядит для Case1[Fn, T].

Для map(f) в A :: B :: ... :: HNil компилятор должен найти implicits для Case1[f.type, A], Case1[f.type, B] и т.д.

В случае List[Int] :: HNil нужен только неявный Case1 Case1[f.type, List[Int]].

Обратите внимание, что Case1 определяется следующим образом:

type Case1[Fn, T] = Case[Fn, T :: HNil]

Итак, мы должны найти неявное значение для Case[f.type, List[Int] :: HNil].

В случае, если f является object, одним из мест для поиска implicits является f поля и методы. Поэтому компилятор найдет Case, определенный в f.

Ответ 2

Я не профессионал, поэтому @miles-sabin и @travis-brown могут дать полный и более четкий ответ, но mb я тоже могу попробовать (он не является полным и не показывает все формальные проблемы):

  • iterateOverHList Это полиморфная функция, расширяющая Poly1, и если вы посмотрите на реализацию этой (Poly1) черты, вы увидите, что в качестве аргументов требуется только один объект, набранный в вашем exmpl как L[T];

  • Функция at точно означает (смотрите реализацию ниже): "в случае типа L[T] примените функцию внутри at, поэтому в вашем методе exmpl iterator вашего объекта. так что вы можете писать разные неявные функции, которые могут применяться на разных типах, полезно, когда вы проходите через HList (например, с картой) с разными и сложными типами.

Реализация Poly признаков и доказательств моих слов выше вы можете найти здесь: http://xuwei-k.github.io/shapeless-sxr/shapeless-2.10-2.0.0-M1/polyntraits.scala.html Здесь мы видим, что черта Poly1 такова:

trait Poly1 extends Poly { outer =>
    type Case[A] = poly.Case[this.type, A :: HNil]
    object Case {
        type Aux[A, Result0] = poly.Case[outer.type, A :: HNil] { type Result = Result0 }
    }

    class CaseBuilder[A] {
        def apply[Res](fn: (A) => Res) = new Case[A] {
            type Result = Res
            val value = (l : A :: HNil) => l match { case a :: HNil => fn(a) }
        }
    }

    def at[A] = new CaseBuilder[A]
}

Ответ 3

Это трудно найти, поскольку классы PolyN в бесформенном автоматически генерируются с помощью Boilerplate.scala.

Все, кроме Poly0, которое вы можете увидеть здесь

Короче... Это всего лишь метод на Poly1