2013-11-20 5 views
1

У меня возникли проблемы с получением моего кода с параметризованными типами для передачи компилятора scala. Моя цель состоит в том, чтобы иметь возможность выражать пары (Predicate, Action), как показано в объекте MyProg.Ограничения типа по функциям

trait ProgBase { 
    type Predicate[T] = T => Boolean 
    type Action[T] = T => Unit 

    private var prog = List[(Predicate[Any], Action[Any])]() 

    final def on[T <: Any](pred: Predicate[T])(action: Action[T]) = { 
    prog = (pred, action) :: prog // gives type mismatch 
    } 

    // remainder of trait elided 
} 

object MyProg extends ProgBase { 
    on[String](s => !s.isEmpty) { s => 
    println(s + " is not empty") 
    } 

    on[Int](i => i.isValidByte) { i => 
    println(i + " can fit in a byte") 
    } 
} 

Указав, что T имеет верхнюю грань Any, я надеялся, что это успокоит компилятор, но очевидно, я что-то не хватает:

[error] ......ProgBase.scala:8 type mismatch; 
[error] found : (T => Boolean, T => Unit) 
[error] required: (Any => Boolean, Any => Unit) 
[error]  prog = (pred, action) :: prog 
[error]       ^

ответ

1

Прежде всего, ответить на ваш вопрос, если вы пишете:

private var prog = List[(Predicate[_ <: Any], Action[_ <: Any])]() 

Все готово. Мы должны использовать подстановочные знаки, потому что тип элементов неизвестен.

Во-вторых, может быть, вы неправильно набрали, вы не можете использовать on функцию, как вы использовали его, использовать что-то вроде:

on[String](s => !s.isEmpty)(s => !s.isEmpty) 

Это вызвано несоответствием типа: type Action[T] = T => Unit но println имеет тип Unit, так как вариант u может просто написать: type Action = Unit. Очевидно, вы можете избежать использования этого псевдонима типа вообще.

В-третьих, может быть, вы уже знаете, и я shoudn't вам сказать, что на самом деле, вы потеряете всю информацию о предикатных типов - давайте проверим это с помощью Scala отражение:

import scala.reflect.runtime.{universe => ru} 
def getTypeTag[T: ru.TypeTag](obj: T) = ru.typeTag[T] 

val s: String = "123" 
val i: Int = 123 

on[String](s => !s.isEmpty)(s => !s.isEmpty) 
on[Int](i => i.isValidByte)(i => i.isValidByte) 

getTypeTag((MyProg.prog.head._1)).tpe =:= ru.typeOf[(String) => Boolean] //>false! 

Таким образом, вы видите проблему ,

Чтобы справиться с этим, вы можете использовать гетерогенные списки. Списки и другие различные могущественные структуры, которые вы можете найти в бесформенном: https://github.com/milessabin/shapeless

+0

Подсказка для подсказки была идеальной! Да, я обманул тело Действия, исправлю. И СПАСИБО за хедз-ап по третьему вопросу, который, я думаю, объясняется стиранием типа. Посмотрите на бесформенную. – yotommy

+0

Я хочу добавить, что нет необходимости использовать '<: Any', потому что' Any' является супертипом всех типов. Но, мне кажется, ты это знаешь. – DaunnC

Смежные вопросы