问题
I am attempting to refactor a function (found towards the end of this StackOverflow answer) to make it slightly more generic. Here's the original function definition:
def tryProcessSource(
file: File,
parseLine: (Int, String) => Option[List[String]] =
(index, unparsedLine) => Some(List(unparsedLine)),
filterLine: (Int, List[String]) => Option[Boolean] =
(index, parsedValues) => Some(true),
retainValues: (Int, List[String]) => Option[List[String]] =
(index, parsedValues) => Some(parsedValues)
): Try[List[List[String]]] = {
???
}
And here is to what I am attempting to change it:
def tryProcessSource[A <: Any](
file: File,
parseLine: (Int, String) => Option[List[String]] =
(index, unparsedLine) => Some(List(unparsedLine)),
filterLine: (Int, List[String]) => Option[Boolean] =
(index, parsedValues) => Some(true),
transformLine: (Int, List[String]) => Option[A] =
(index, parsedValues) => Some(parsedValues)
): Try[List[A]] = {
???
}
I keep getting a highlight error in the IntelliJ editor on Some(parsedValues)
which says, "Expression of type Some[List[String]] doesn't conform to expected type Option[A]". I've been unable to figure out how to properly modify the function definition to satisfy the required condition; i.e. so the error goes away.
If I change transformLine
to this (replace the generic parameter A
with Any
)...
transformLine: (Int, List[String]) => Option[Any] =
(index, parsedValues) => Some(parsedValues)
...the error goes away. But, I also lose the strong typing associated with the generic parameter.
Any assistance on with this is very much appreciated.
回答1:
In transformLine: (Int, List[String]) => Option[A] = (index, parsedValues) => whatever
, parsedValues
obviously has type List[String]
, and so Some(parsedValues)
is Some[List[String]]
. There is simply no reasonable default value for transformLine
.
You can change its type to (Int, A) => Option[A]
or (Int, List[A]) => Option[List[A]]
depending on what you need, and change the previous arguments as well, but you'll get stuck on the fact that lines are String
s, so you'll have to convert them to A
somewhere.
回答2:
After reading and re-reading Alexey Romonov's answer and Lee's comment, it gave me a clue into how to refactor this to get it working. Additionally, I think it might also implies a guideline regarding providing default values to a function.
If I am understand it correctly, I am trying to combine a concrete, in this example case List[String]
in the transform parameter default, with a generic type, in this case Option[A]
. Essentially, this overlaps the boundary upon which a generic copy of the function is instantiated by the compiler for the specific user provided type and the explicitly provided List[String]
. This leads me to the following guideline regarding defining generic functions:
When transforming a concrete function to make it generic, each parameter with a default value which interacts directly with any of the generic parameters likely needs to be removed and placed into an enclosing concrete function which forwards the call to the generic function.
So with this guideline in mind, let's rework the original code...
The concrete function looks like this (very similar to the original pre-generic-ified version which also included the desired concrete default parameters):
def tryProcessSource(
file: File,
parseLine: (Int, String) => Option[List[String]] =
(index, unparsedLine) => Some(List(unparsedLine)),
filter: (Int, List[String]) => Option[Boolean] =
(index, parsedValues) => Some(true),
transform: (Int, List[String]) => Option[List[String]] =
(index, parsedValues) => Some(parsedValues)
): Try[List[List[String]]] =
tryProcessSourceGeneric(file, parseLine, filter, transform)
And the generic-ified function looks like this (notice the lack of any parameter default values):
def tryProcessSourceGeneric[A, B](
file: File,
parseLine: (Int, String) => Option[A],
filter: (Int, A) => Option[Boolean]
transform: (Int, A) => Option[B]
): Try[List[B]] = {
???
}
Again, a huge thank you to Alexey and Lee for helping me struggle through this.
来源:https://stackoverflow.com/questions/34294100/how-do-i-define-a-function-parameter-default-associated-with-a-generic-parameter