I haven’t found a previous discussion on this topic, so sorry for the noise if it was already discussed, or even worked on in Dotty - I don’t know the status of Dotty either.
In TypeScript you can declare generic functions just as in Scala:
function id<A>(a: A): A {
return a
}
However in TypeScript functions are considered actual values, so the above is equivalent to this:
const id = <A>(a: A) => a
And just to make it clear, id
is a plain value and its type is that of a generic function:
const id2: <A>(a: A) => A = id
So we can declare these generics anywhere, including in function return types. So now currying actually works in a totally non-useless way:
class Box<A> {
constructor(public readonly value: A) {}
}
function map2<A, B>(ba: Box<A>, bb: Box<B>): <C>(f: (a: A, b: B) => C) => Box<C> {
return f =>
new Box(f(ba.value, bb.value))
}
Just to make that clear
// Infered type: <C>(f: (a: number, b: string) => C): Box<C>
const pf = map2(new Box(2), new Box("x"))
pf((a, b) => `${a}${b}`)
//=> Box { value: '2x' }
Here’s the Scala equivalent:
case class Box[A](value: A)
def map2[A, B, C](ba: Box[A], bb: Box[B])(f: (A, B) => C): Box[C] =
Box(f(ba.value, bb.value))
This works for plain function calls:
map2(Box(2), Box("x"))((a, b) => s"$a$b")
// res: Box[String] = Box(2x)
But then it breaks when doing currying at the call site:
val pf = map2(Box(1), Box("x")) _
// pf: ((Int, String) => Nothing) => Box[Nothing] = $$Lambda$1323/1759889326@68bd8ca7
And note this doesn’t work if we do a def
either:
def pf = map2(Box(1), Box("x")) _
// pf: ((Int, String) => Nothing) => Box[Nothing]
Or in other words, currently in Scala currying is only a trick to infer the type of the f
parameter when doing a normal function call (with all params provided), but it’s completely useless for partial application when generics are involved.
Is this something that can or is being fixed? In Dotty maybe?