2015-07-02 3 views
0

Во-первых, некоторые фон:Кастинг объекта Scala в общий тип?

В настоящее время я пишу общий решатель для определенного класса проблем (в частности, структурный решатель SVM) в Scala. Чтобы использовать это, пользователь должен реализовать интерфейс.

Рассмотрим упрощенную версию интерфейса:

trait HelperFunctions[X, Y] { 
    def func1(x: X, y: Y): Y 
    def func2(y1: Y, y2: Y): Int 
} 

и простую реализацию: (. Обратите внимание, что реализация имеет которая должна быть предоставлена ​​в форме объекта)

object ImplFunctions extends HelperFunctions[Vector[Double], Double] { 
    def func1(x: Vector[Double], y: Double): Double = { ... } 
    def func2(y1: Double, y2: Double): Int = { .. } 
} 

Теперь проблема: Мне нужно написать диагностический набор, который помогает пользователю проверить разумность его функций. Пример теста на здравомыслие будет включать в себя нечто вроде func1(..), являющееся положительным для всех x и y. Для этого я изложил, написав блок-тесты стиля BDD, используя ScalaTest.

Обратите внимание, что диагностический набор должен быть общим, чтобы работать с любым объектом, который расширяет HelperFunctions[X, Y]. Высокоуровневая картина того, как я планировал это сделать: сначала предоставив все тесты на чувствительность, разработанные для общего назначения X и Y. Затем пользователь просто заменяет, скажем ???, ImplFunctions и запускает пакет.

Но, оказывается, я не нашел изящного подхода к лечению ImplFunctions как общего HelperFunctions[X, Y]. Вот вкус того, что я пытался до сих пор:

import org.scalatest._ 

class ApplicationDiag extends FlatSpec { 

    // Option 1: 
    // Cast the ImplFunctions into a generic type 
    // ERROR: type mismatch; found : ImplFunctions.type, required : HelperFunctions[X, Y] 
    val helpers: HelperFunctions[X, Y] = ImplFunctions 
    // OR 
    def helpers[X, Y](): HelperFunctions[X, Y] = ImplFunctions 


    // Option 2: User fills up the right side, no type specified for the value 
    // WORKS. But, cannot explicitly state types 
    val helpers = ImplFunctions 

    "func1" should "be positive" in { 
    // ... the check as described previously 
    } 

} 

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

Примечание: 1. Я полностью открыт для альтернативных конструкций диагностического набора. 2. реальный интерфейс: HelperFunctions и в реальном мире приложений: ImplFunctions

+2

Если вы хотите, чтобы ваши типы были совпадающими или противоречивыми, вы должны объявить их как таковые с помощью синтаксиса '+ X' /' -X'. Вам не нужно бросать. – lmm

ответ

0

Я не знаю, как вы пишете ваши общие тесты, но, возможно, вам следует рассмотреть возможность использования type classes.

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

trait Helpers[A] { 
    def f(a: A): A 
} 

и реализацию

object IntImpl extends Helpers[Int] { 
    def f(a: Int) = -a 
} 

К сожалению, Helpers[A] не требует каких-либо ограничений на A, которые были бы хорошо. Но вы, вероятно, не хотите изменять библиотеку.

Это еще можно написать общий набор тестов для некоторых A с:

class Diag[A : Numeric](h: Helpers[A]) { 
    val fromInt = implicitly[Numeric[A]].fromInt _ 

    // just some assertions, using scalatests here should also work 
    assert(h.f(fromInt(0)) == fromInt(0)) 
    assert(h.f(fromInt(1)) == fromInt(1)) // will fail with IntImpl 
} 

Этот комплект может быть использован с любой A, для которых мы имеем реализацию Numeric типа класса (например, Int).

Конкретный люкс теперь может быть создан с:

new Diag(IntImpl) 

или если тест рамка требует класса

class ImplDiag extends Diag(IntImpl) 

Этого подход имеет то преимущество, что она полностью Типобезопасная. Вам не нужно ничего делать, а подпись Diag четко определяет, что требуется для запуска пакета.