I'm trying to compose some functions with compound types in their type parameters:
trait Contains[T]
trait Sentence
trait Token
def sentenceSegmenter[T] = (c: Contains[T]) => null: Contains[T with Sentence]
def tokenizer[T <: Sentence] = (c: Contains[T]) => null: Contains[T with Token]
My main goal is to be able to compose them with something as simple as:
val pipeline = sentenceSegmenter andThen tokenizer
However, that produces a compile error, because Scala infers that the type of tokenizer
needs to be Contains[? with Sentence] => ?
:
scala> val pipeline = sentenceSegmenter andThen tokenizer
<console>:12: error: polymorphic expression cannot be instantiated to expected type;
found : [T <: Sentence]Contains[T] => Contains[T with Token]
required: Contains[? with Sentence] => ?
val pipeline = sentenceSegmenter andThen tokenizer
^
I tried a slightly different definition of tokenizer
that more closely matches the type inferred by Scala, but I get a similar error:
scala> def tokenizer[T] = (c: Contains[T with Sentence]) => null: Contains[T with Sentence with Token]
tokenizer: [T]=> Contains[T with Sentence] => Contains[T with Sentence with Token]
scala> val pipeline = sentenceSegmenter andThen tokenizer
<console>:12: error: polymorphic expression cannot be instantiated to expected type;
found : [T]Contains[T with Sentence] => Contains[T with Sentence with Token]
required: Contains[? with Sentence] => ?
val pipeline = sentenceSegmenter andThen tokenizer
^
I can get things to compile if I specify pretty much any type along with sentenceSegmenter
, or if I create a bogus initial function that does not have a type parameter:
scala> val pipeline = sentenceSegmenter[Nothing] andThen tokenizer
pipeline: Contains[Nothing] => Contains[Nothing with Sentence with Sentence with Token] = <function1>
scala> val pipeline = sentenceSegmenter[Any] andThen tokenizer
pipeline: Contains[Any] => Contains[Any with Sentence with Sentence with Token] = <function1>
scala> val begin = identity[Contains[Any]] _
begin: Contains[Any] => Contains[Any] = <function1>
scala> val pipeline = begin andThen sentenceSegmenter andThen tokenizer
pipeline: Contains[Any] => Contains[Any with Sentence with Sentence with Token] = <function1>
I wouldn't mind the type Any
or Nothing
being inferred, since I don't really care what T
is. (I mainly care about the with XXX
part.) But I'd like it to be inferred, rather than having to specify it explicitly, or supplying it via a bogus initial function.