Введите безопасную цепочку методов, которая не допускает повторения операций.

Я хочу реализовать цепочку методов, как в этих вопросах:

Рекомендации по реализации трейта Scala, поддерживающего цепочку методов ;

Scala DSL: связывание методов с методами без параметров

Однако я хочу, чтобы после использования "свойства" его больше нельзя было использовать. Например, предположим, что у меня есть класс «Myclass», для которого я хочу разрешить использование определения «foo» и определения «bar» не более одного раза, и меня не волнует окончательный возвращаемый тип. Таким образом:

val c = new Myclass
c foo //ok !
c foo bar // ok!
c foo foo // refuse to compile
c foo bar foo //refuse to compile

Я борюсь с этой проблемой некоторое время, и мое зрение начинает становиться нечетким! Однако я пытался использовать неявные классы, нужно ли им анализировать объекты, которые не использовали связанное свойство, и я не могу найти, как это сделать, нужно ли им «потреблять» свойство, удаляя его из доступного свойства объекта, и, опять же, я не могу найти, как это сделать.

В настоящее время я ищу API отражения, но для меня это все еще немного неясно.

Помощь приветствуется! знак равно


person Coo LHibou    schedule 26.07.2013    source источник


Ответы (2)


См. Фантомные типы в Haskell и Scala автор Джеймс Айри.

Вы также можете использовать безопасный шаблон построителя:

trait TTrue
trait TFalse

@annotation.implicitNotFound(msg = "Cannot call same method twice.")
sealed abstract class =^=[From, To]
object =^= {
  private val singleton_=^= = new =^=[Any, Any]{}
  implicit def tpEquals[A]: A =^= A = singleton_=^=.asInstanceOf[A =^= A]
}

class Myclass[TFoo, TBar, TBuz] private(){
  def foo(implicit e: TFoo =^= TFalse) = new Myclass[TTrue, TBar, TBuz]
  def bar(implicit e: TBar =^= TFalse) = new Myclass[TFoo, TTrue, TBuz]
  def buz(implicit e: TBuz =^= TFalse) = new Myclass[TFoo, TBar, TTrue]
}

object Myclass{
  def apply() = new Myclass[TFalse, TFalse, TFalse]
}

использовать так

scala> Myclass().foo.bar.buz
res0: Myclass[TTrue,TTrue,TTrue] = Myclass@12ac706a

scala> Myclass().bar.buz.foo
res1: Myclass[TTrue,TTrue,TTrue] = Myclass@1e69dff6

scala> Myclass().foo.buz.foo
<console>:12: error: Cannot call same method twice.
              Myclass().foo.buz.foo
                                ^
person senia    schedule 26.07.2013
comment
+1 для конструкторов шрифтов. Но эта реализация тесно связана с количеством методов, как насчет добавления 10 новых методов? И такая ошибка в производстве была бы странной - person 4lex1v; 26.07.2013
comment
@AlexIv: для 10 методов вам нужно добавить 10 параметров типа. Исправлено сообщение об ошибке. Это ошибка компиляции, а не ошибка производства во время выполнения. - person senia; 26.07.2013
comment
Спасибо за ответ. Я понял основную идею: у вас есть флаг TTrue/TFalse для каждой опции, которую вы переключаете, когда опция активирована. Чтобы обнаружить активацию параметра во время компиляции, вы запрашиваете неявное создание экземпляра объекта, объекта, который может быть неявно создан, если и только если флаг имеет правильное значение. Следовательно, если параметр был вызван, флаг имеет значение true, неявное создание экземпляра невозможно, и компилятор потерпел неудачу, выполнив тест в аннотации. Я думаю, что это очень элегантное решение. - person Coo LHibou; 30.07.2013
comment
Однако моя цель состоит в том, чтобы использовать декоратор шаблонов для предоставления расширяемой опциональной структуры, поэтому я заранее не знаю, какие будут варианты, поэтому я не могу использовать это решение. Я думаю, что для этого можно что-то сделать с помощью изменяемой карты... Я изучаю ее, а также решение типа макроса, которое может позволить напрямую генерировать соответствующий тип - person Coo LHibou; 30.07.2013

здесь вы можете найти улучшенное решение:

http://jim-mcbeath.blogspot.fr/2009/09/type-safe-builder-in-scala-part-3.html

(что на самом деле зависит от фантомных типов)

person Coo LHibou    schedule 23.10.2013