0

I'm struggling to find a generic type signature for a cons cell, that allows for the selector function to be typed.

I.e. The code I want to be typed:

const cons = (head, tail) => selector => selector(head, tail);

I want to assign a generic type, where type T is the head and type V is the tail.

Some of my elaborate typing attempts have been:

const cons: <T,V>(head: T, rest: V) => (selector: (head: T, rest: V) => T | V) => T | V 
    = (head, rest) => selector => selector(head, rest);

The problem with the above code, is that I cannot find a type signature that works for the selector function head, with the implementation:

const head = list => list((head, rest) => head)

I always get the error "Expected 2 arguments but got 1." under list((head, rest) => head).

I just can't get the generic type to work! Any help would be greatly appreciated! Thank you!

Edit - Added example of expected behaviour (without types)

const cons = (head, tail) => selector => selector(head, tail);
const head = list => list((head, tail) => head);
const rest = list => list((head, tail) => tail);
let someList = cons(1, cons(2, cons(3, null)));
head(someList);
// returns: 1
rest(someList);
// returns: cons(2, cons(3, null))
YouCodeThings
  • 590
  • 3
  • 13
  • It is not clear what you are trying to do. Is it to call `cons(head)`? – Rodris Jul 21 '17 at 15:10
  • @RodrigoPedrosa I've added an example of expected behaviour without the types added. If it's still confusing I can elaborate more. Thank you for your question. – YouCodeThings Jul 22 '17 at 14:42

1 Answers1

0

Your const type is exactly the same as mine. I just split the many parts for clarity. The only new type I have added is the selectorFuncWrapper, which I think is what you were looking for.

The original code is preserved. Check if it is good for you.

type selector<H, T> = (head: H, tail: T) => (H | T);
type selectorFunc<H, T> = (selector: selector<H, T>) => (H | T);
type consFunc<H, T> = (head: H, tail: T) => selectorFunc<H, T>;
type selectorFuncWrapper<H, T> = (list: selectorFunc<H, T>) => selectorFunc<H, T>;

const cons: consFunc<number, any> = (head, tail) => selector => selector(head, tail);

const head: selectorFuncWrapper<number, any> = list => list((head, tail) => head);
const rest: selectorFuncWrapper<number, any> = list => list((head, tail) => tail);

let someList = cons(1, cons(2, cons(3, null)));

head(someList);
// returns: 1
rest(someList);
// returns: cons(2, cons(3, null))
Rodris
  • 2,603
  • 1
  • 17
  • 25
  • Thank you so much for the answer. Unfortunately if you call `head(rest(someList));` there is still a TypeError: `Argument of type 'selector' is not assignable to parameter of type 'selectorFunc'`. – YouCodeThings Jul 23 '17 at 23:13
  • I see. I have changed the `selectorFuncWrapper` return type. It shall fix this problem. Can you try? – Rodris Jul 24 '17 at 01:06