SimonMeskens / TypeProps

Small library for describing HKTs in TypeScript
Apache License 2.0
32 stars 2 forks source link

Issues with small tuple example #7

Closed jack-williams closed 6 years ago

jack-williams commented 6 years ago

I might be implementing this wrong, but here is a small example I ran into trouble with. I extended the sample code posted in the playground here.

function tupleMap<A,B,F extends StaticFunctor<F>>(l: Generic<F,[A]>, f: (x: A) => B): Generic<F,[[B,B]]> {
    const mapper: (a: A) => [B,B] = x => [f(x),f(x)];
    return functor.map(mapper, l);
}

const values: number[] = [1,2,3]
const result = tupleMap(values, (x: number) => x + 1)

The implementation of tupleMap doesn't type-check, it doesn't seem to like mapper[1]. Also, the call-site doesn't type check, though it does work if you explicitly instantiate the parameters:

const result = tupleMap<number, number, number[]>(values, (x: number) => x + 1)

Is using number[] the correct way to pass the functor type?

[1] Error message:

Argument of type '(a: A) => [B, B]' is not assignable to parameter of type '(a: TypeProps<TypeProps<F, [A]>[Match<F>]["construct"], never>[Match<TypeProps<F, [A]>[Match<F>][...'.
  Types of parameters 'a' and 'a' are incompatible.
    Type 'TypeProps<TypeProps<F, [A]>[Match<F>]["construct"], never>[Match<TypeProps<F, [A]>[Match<F>]["con...' is not assignable to type 'A'.
      Type '{} | NonNullable<TypeProps<F, [A]>[Match<F>]["construct"]>' is not assignable to type 'A'.
        Type '{}' is not assignable to type 'A'. [2345]
SimonMeskens commented 6 years ago

You're overcomplicating it. You know what the specific types are, so you can just do this:

function tupleMap<A, B>(
    l: A[],
    f: (x: A) => B
) {
    const mapper: (a: A) => [B, B] = x => [f(x), f(x)];
    return functor.map(mapper, l);
}

const values = [1, 2, 3];
const result = tupleMap(values, (x: number) => x + 1);
SimonMeskens commented 6 years ago

Most of the time, inference works and you don't even need to specify anything related to Functor

jack-williams commented 6 years ago

Does the signature tupleMap<A, B>(l: A[], f: (x: A) => B) not fix the functor to be an array? I wouldn't be able to use that function on other functor instances like Maybe<A>. I was trying to write one that was generic over the container.

SimonMeskens commented 6 years ago

Ah, sorry, I misunderstood, you want this one then:

function tupleMap<F,B>(l: F, f: (x: Parameters<F>[0]) => B): Generic<F,[[B,B]]> {
    const mapper: (a: Parameters<F>[0]) => [B,B] = x => [f(x),f(x)];
    return functor.map(mapper, l);
}

const values = [1,2,3]
const result = tupleMap(values, (x: number) => x + 1)
jack-williams commented 6 years ago

Yep that works, cheers!

Also works for:

function tupleMap<A extends Parameters<F>[0], B, F extends StaticFunctor<F>>(l: Generic<F,[A]>, f: (x: A) => B): Generic<F,[[B,B]]> {
    const mapper: (a: A) => [B,B] = x => [f(x),f(x)];
    return functor.map(mapper, l);
}