I have a case-class that takes arguments with a bounded type, however when using the case-class extractor the type system appears to be losing the bounds and inferring 'Any' instead.
For example:
trait Expr[T]
case class IntLit(value:Int) extends Expr[Int]
case class GreaterThan[T <% Ordered[T]]( a:Expr[T], b:Expr[T] ) extends Expr[Boolean]
object TestRuntime {
def execute[T]( expr:Expr[T] ):T = expr match {
case IntLit(value) => value
// ---> This line fails because the compiler thinks a and b are Expr[Any]
// Instead of Expr[_ <% Ordered[_]]
// error: value > is not a member of Any
case GreaterThan(a,b) => execute(a) > execute(b)
// ---> Whereas this line works correctly.
/// EDIT: Actually, no it doesn't, it throws a ClassCastException!
/// T is Boolean,
/// Whereas we're expecting a new type U <: Ordered[U]
case gt:GreaterThan[T] => execute(gt.a) > execute(gt.b)
}
}
Is this simply a limitation of Scalas type inference, or am I missing something?
I've also attempted to achieve the same result using the Ordering[T] typeclass using a context bounds (This would be preferable)
case class GreaterThan[T : Ordering]( a:Expr[T], b:Expr[T] )
However I can't figure out how to access the typeclass instance inside the match{} block without adding a method to GreaterThan itself (Which somewhat defeats the point of using a typeclass for this purpose.)
Effectively, what I'm trying to do is port this Haskell to Scala
{-# LANGUAGE GADTs #-}
data Expr a where
StringLit :: String -> Expr String
IntLit :: Int -> Expr Int
Equals :: (Eq a) => (Expr a) -> (Expr a) -> Expr Bool
GreaterThan :: (Ord a) => (Expr a) -> (Expr a) -> Expr Bool
runExpr :: Expr a -> a
runExpr (IntLit i) = i
runExpr (StringLit s) = s
runExpr (Equals a b) = (runExpr a) == (runExpr b)
runExpr (GreaterThan a b) = (runExpr a) > (runExpr b)