Hacker News new | ask | show | jobs
by zcesur 2050 days ago
Say you'd like to have an interface for things that are 'mappable'. For example, for arrays we could write:

    interface Mappable<Array> {
      map<A, B>(f: (a: A) => B, fa: Array<A>): Array<B>
    }
Likewise, for `Promise`s we could write:

    interface Mappable<Promise> {
      map<A, B>(f: (a: A) => B, fa: Promise<A>): Promise<B>
    }
But in order to generalize this interface to an arbitrary type constructor such that `F: * -> *`, we would need to write

    interface Mappable<F> {
      map<A, B>(f: (a: A) => B, fa: ?): ?
    }
which is not possible in TypeScript since it does not support higher-kinded types or type parameters that take type parameters or parametrized modules.
2 comments

Not possible, but an approximation:

  interface Mappable<P extends Mappable<P, unknown>, T> {
    flatMap<U>(f: (x: T) => Mappable<P, U>): Mappable<P, U>;
  }

  class Maybe<T> implements Mappable<Maybe<unknown>, T> {
    x: T | undefined;

    public flatMap<U>(f: (x: T) => Maybe<U>): Maybe<U> {
        if (this.x) {
            return f(this.x);
        }
        return Maybe.nothing();
    }
  }
Yes, in fact this reminds me of the HKT implementation[1] found in fp-ts[2][3]

    interface HKT<F, A> {
      _URI: F
      _A: A
    }
    
    interface Mappable<F> {
      map<A, B>(f: (a: A) => B, fa: HKT<F, A>): HKT<F, B>
    }
where F is a unique identifier representing the type constructor and A its type parameter.

[1]: https://www.cl.cam.ac.uk/~jdy22/papers/lightweight-higher-ki... [2]: https://github.com/gcanti/fp-ts [3]: https://gist.github.com/gcanti/2b455c5008c2e1674ab3e8d5790cd...

gcanti’s work in Flow and Typescript is amazing and I use it daily :)
Seems like something covered by typeclasses in Haskell, right?
Seems like it, but typeclasses are inherently anti-modular, they provide a globally coherent unique instance. consider the Ord typeclass giving a single ordering for a specific type. To reverse the order you need to create a new type with a new instance of ord which reverses it.

Where in a module system its perfectly fine to have multiple instances of Ord for a given type. One gives global consistency where the other gives local consistency.

When you put it like that, modules sound more powerful than typeclasses. Is there any situation where typeclasses are superior to modules?
I think the extra power comes with cognitive overhead, I.e. operators are now relative to some module, and you're stuck with that overhead whether or not you actually use the power or not.

Trying to stay neutral, I think its no suprise that some people prefer typeclasses...

In addition to @ratmice's comment, check out this post[1] on Existential Type. I've dabbled in Haskell myself with not much experience in ML, so I found it interesting to see how ML modules differ from Haskell typeclasses. Though they seem to be equi-expressive for the most part.

[1]: https://existentialtype.wordpress.com/2011/04/16/modules-mat...