Как улучшить вывод типа Scala с помощью параметров типа, которые не отображаются в первом списке параметров? - PullRequest
6 голосов
/ 05 августа 2011

Чтобы проиллюстрировать мою точку зрения, вот пример:

abstract class Wrapper[A](wrapped: A) {

  protected def someCondition: Boolean

  def fold[B](whenTrue: => B)(whenFalse: => B): B =
    if (someCondition) whenTrue else whenFalse

}

Я пытаюсь добавить метод fold, основанный на произвольном условии, определенном для упакованного типа A.Проблема с кодом выше состоит в том, что он не будет компилироваться, хотя он может возвращать Any:

wrapper.fold("hi")(42)

, потому что к тому времени, когда компилятор достигает второго списка параметров, B уже былПредполагается, что String.Предположим, мы не хотим писать аннотацию типа.Мы можем попытаться изменить fold на это:

def fold[B, B0 >: B](whenTrue: => B)(whenFalse: => B0): B0

, но этот также не работает, поскольку B0 уже был разрешен как String в концепервый список параметров, хотя он вообще не отображается!Простое решение, конечно, состоит в том, чтобы иметь один список параметров, но для примера, скажем, я хочу сохранить два списка параметров и попытаться заставить его работать ... В идеале, мы должны иметь возможность задержка разрешение B0.Было бы здорово, если бы мы могли написать что-то вроде этого:

def fold[B](whenTrue: => B)[B0 >: B](whenFalse: => B0): B0

Но, к сожалению, это не работает.Есть ли какие-нибудь обходные пути?

(я даю первый ответ, но я, конечно, ищу и другие обходные пути).

Ответы [ 2 ]

5 голосов
/ 05 августа 2011

Похоже, вы хотите подражать, благодаря компиляции, поведению и цели класса Either. Что вы можете сделать, это следующее: ваша складка вернет объект Either и получит из него значение B0:

abstract class Wrapper[A](wrapped: A) {

  protected def someCondition: Boolean

  def fold[A, B](whenTrue: => B)(whenFalse: => A): Either[A, B] =
    Either.cond(someCondition, whenTrue, whenFalse)

}

И пусть неявное преобразование either2mergeable класса Either сделает работу:

scala> new Wrapper[Unit] {def someCondition = true}
res0: Wrapper[Unit] = $anon$1@77026e40

scala> res0.fold(42)("hi").merge
res1: Any = 42

Pro:

  • Структура Either позволяет напрямую получать типы A и B
  • Вы можете проверить, какая часть была применена во время сгиба

Con:

  • Вы не получите результат напрямую
3 голосов
/ 05 августа 2011

Одним из решений является создание временного экземпляра класса, который определяет метод apply, имитирующий второй список параметров, который сам имеет параметр типа B0:

abstract class Wrapper[A](wrapped: A) {

  // ... as before...

  def fold[B](whenTrue: => B) = new FoldRequest[B](whenTrue)

  class FoldRequest[B](whenTrue: => B) {
    def apply[B0 >: B](whenFalse: => B0) =
      if (someCondition) whenTrue else whenFalse
  }
}

Тогда все работает правильно. Можем ли мы даже представить, что def fold[B](whenTrue: => B)[B0 >: B](whenFalse: => B0): B0 можно интерпретировать как синтаксический сахар для этого?…

...