Scala: Как я могу создать функцию, которая позволяет мне использовать запись через точку при ее вызове?

Я был смущен этим некоторое время, даже несмотря на то, что прочитал Руководство по стилю Scala - Метод Вызов несколько раз.

Я хочу иметь возможность вызывать этот метод

def foldRVL[A,B](l: List[A], z: B)(f: (A, B) => B) = //"Right-Via-Left"
  l.reverse.foldLeft(z)((a, b) => f(b, a))

используя запись через точку, как это List(1,2,3).foldRVL(0)(_ + _).

А не так: foldRVL(List(1,2,3), 0)(_ + _).

Кроме того, иногда я видел код, который показывает методы, которые на самом деле либо принимают в своей сигнатуре нулевые параметры, либо на один параметр меньше, чем я ожидал, и все же правильно принимают параметр с использованием точечной записи. Как это работает? Я спрашиваю об этом, потому что эти методы работают с точечной нотацией, поэтому, возможно, если бы я написал что-то подобное, я мог бы решить свою проблему.


person Nicholas Montaño    schedule 24.07.2015    source источник
comment
Вы знакомы с шаблоном «Прокачай мою библиотеку» в Scala? Если я правильно понимаю, это именно то, что вы хотели бы использовать.   -  person childofsoong    schedule 25.07.2015
comment
Для вас очень важно понять, что такое this, и это не так сложно: это ссылка на экземпляр окружающего класса, для которого был вызван метод. См. en.wikipedia.org/wiki/This_(computer_programming).   -  person JimN    schedule 25.07.2015


Ответы (2)


Для первой части вашего вопроса вам, вероятно, нужно взглянуть на неявные классы< /а>:

  implicit class RichRVLList[A](l:List[A]) {
    def foldRVL[B](z: B)(f: (A, B) => B) = //"Right-Via-Left"
      l.reverse.foldLeft(z)((a, b) => f(b, a))
  }

  List(1,2,3).foldRVL(1)(_ + _)  // output: res0: Int = 7

Вы можете «обогатить» существующий класс, используя неявную оболочку, чтобы «добавить» новые методы.

Что касается второй части, возможно, вам нужны неявные параметры. Неявные параметры выводятся из текущей области по типу. Есть некоторые предопределенные неявные значения, такие как Numerics, которые использовались в приведенном ниже примере:

  def product[T](els:TraversableOnce[T])(implicit num:Numeric[T]) = {
    els.fold(num.one)((x1, x2) => num.times(x1, x2))
  }      

  product(List(1, 2, 3)) // res1: Int = 6
  product(List(1, 2.5, 3)) //res2: Double = 7.5
person Aivean    schedule 25.07.2015

Сун указал, что я на самом деле ищу шаблон «Прокачай мою библиотеку», который я затем просмотрел и реализовал следующим образом для обработки рассматриваемого метода:

implicit class BlingList[+A](l: List[A]) {
  def foldRVL[B](z: B)(f: (A, B) => B): B = //"Right-Via-Left"
    l.foldLeft(z)((a, b) => f(b, a))
}

Насколько я понимаю, ключевым элементом для разрешения точечной нотации является наличие конструкции класса, которая принимает параметры типа, который я хочу «прокачать». В этом случае у меня есть список, и я хочу вызвать foldRVL в списке после того, как запишу список, например: List(something).foldRVL(z)(f: A => B). Поэтому мне нужен класс, который принимает параметр List[A], чтобы я мог написать такой метод в первом фрагменте кода.

Ключевое слово implicit используется для того, чтобы я мог добавлять методы к существующему class List без необходимости создавать отдельную библиотеку методов. Каждый раз, когда перед foldRVL встречается префикс List, он будет неявно преобразован в BlingList, потому что компилятор увидит List, присоединенный к методу, которого нет в class List. Поэтому он будет искать любые неявные методы, определенные в области видимости, которые имеют метод foldRVL и принимают List в качестве аргумента, и находит, что implicit class BlingList имеет определенный метод foldRVL и принимает List[A]. Поэтому теперь я могу написать:

List(1,2,3).foldRVL(0)(_ + _) // in some IDE's, foldRVL will be underlined to show that
res0: Int = 6                 // an implicit conversion is being made

"Пример неявного класса Scala 2.10" более подробно рассказывает об этом. Мой любимый указатель из этого поста — поместить все неявные классы, которые вы ожидаете использовать в вашем текущем пакете, и любые подпакеты внутри package object, таким образом, вам не придется загромождать какие-либо из ваших классов или объектов неявными определениями классов. , и вам не нужно их импортировать. Тот факт, что они используют один и тот же пакет, автоматически импортирует их благодаря расширению package object.

person Nicholas Montaño    schedule 25.07.2015