- About Scala
- Documentation
- Code Examples
- Software
- Scala Developers
variable type parameters
Sat, 2010-01-23, 21:33
Hi,
Is there a good way to define functions that work over N number of type
parameters? I think the answer is yes, along the lines of the HList
heterogeneous list and/or higher-kinded generics, but all I have is a
hunch and am not quite sure where to start.
My use case is taking a regular log statement like:
log.error("some message arg1 is {} arg2 is {}", arg1, arg2);
Which is currently just `error(String, Object...)`and change it to:
val error = new Error[Int, String]("some message ...")
Then later use error as:
error(arg1, arg2) --> error.apply(arg1, arg2)
I can work this out by defining Error0, Error1[T], Error2[T,U], etc.,
but it'd be nice to build it up, e.g.:
val error = Error("Some message").with[Int].with[String]
Or something like that where Error starts with its apply method having
no parameters, then with each call to with, we return a new type with
n+1 parameters to its apply method, with the n+1-th parameter being
strongly typed to whatever T got passed to the latest with method.
I need to re-read some mono/scalaz/HList stuff, but would appreciate a
hint as well.
Thanks,
Stephen
Mon, 2010-01-25, 21:47
#2
Re: variable type parameters
> Is this the sort of thing you have in mind?
> class Error0(val x: String) {
> type With[T] = Error1[T]
> def With[T] = new Error1[T](x)
> def apply() = x
> }
[snip]
> You can use it like Error("abcd").With[Int].With[String](123,"xyz")
Yes, except I wanted to be fancy and avoid a lot of ErrorX classes. You
are right, this is probably the most practical way to do this.
I was attempting to have some Error[T] where T could be no args, 1 args,
or n args depending on the context.
HList's HCons seems to do this:
http://jnordenberg.blogspot.com/2008/08/hlist-in-scala.html
Though I haven't had the time to read/understand/adapt this approach to
what I want to do. Though given how quick & easy Error0/Error1/etc. is,
I will likely end up going that route anyway.
Thanks,
Stephen
Is this the sort of thing you have in mind?
trait Error {
type With[T] <: Error
def With[T]: With[T]
}
object Error {
def apply(x: String) = new Error0(x)
}
class Error0(val x: String) {
type With[T] = Error1[T]
def With[T] = new Error1[T](x)
def apply() = x
}
class Error1[A](val x: String) {
type With[T] = Error2[A,T]
def With[T] = new Error2[A,T](x)
def apply(a: A) = x + ":" + a
}
class Error2[A,B](val x: String) {
type With[T] = Error3[A,B,T]
def With[T] = new Error3[A,B,T](x)
def apply(a: A, b: B) = x + ":" + a + ":" + b
}
class Error3[A,B,C](val x: String) {
type With[T] = Nothing
def With[T] = error("no more")
def apply(a: A, b: B, c: C) = x + ":" + a + ":" + b + ":" + c
}
You can use it like Error("abcd").With[Int].With[String](123,"xyz")