You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Currently, we define ADT by using interfaces, type synonyms, union type and normal function:
/** -- For comparison, I'll use following Haskell type and type class.class Monoid a where mempty :: a mappend :: a -> a -> adata List a = Nil | Cons a (List a)instance Monoid (List a) where mempty = Nil mappend Nil ys = ys mappend xs Nil = xs mappend (Cons x xs) ys = Cons x $ mappend xs ys**/import{Kind,URIS}from'fp-ts/lib/HKT';interfaceMonoid1<FextendsURIS>{getMempty<A>(): Kind<F,A>;mappend<A>(x: Kind<F,A>,y: Kind<F,A>): Kind<F,A>;}declare module 'fp-ts/lib/HKT'{interfaceURItoKind<A>{List: List<A>;}}constURI: 'List'='List';typeURI=typeofURI;interfaceNil{type: 'Nil';}interfaceCons<A>{type: 'Cons';value: A;next: List<A>;}typeList<A>=Nil|Cons<A>;functionnil(): Nil{return{type: 'Nil'};}functioncons<A>(value: A,next: List<A>): Cons<A>{return{type: 'Cons', value, next };}constlist: Monoid1<URI>={getMempty: nil,mappend<A>(xs: List<A>,ys: List<A>): List<A>{if(xs.type==='Cons')returncons(xs.value,list.mappend(xs.next,ys));elsereturnys;}};
Desired Behavior
So redundant. Definitions are spread out over source code.
And, current way of simulating ad-hoc polymorphisms with type class instance is really, really verbose to use(We must give type class instance definition to ad-hoc polymorphic function every time we call them).
Suggested Solution
Why don't we use classes? class combines definitions into one. also, we can easily infer type class instance from value when we use classes for defining ADT.
Here is my solution:
// For simplification, I skipped processes of type-level defunctionalization for type List.
abstract class Monoid<A> { // Type Class Monoid
public abstract getMempty(): A; // Required operations
public abstract mappend(x: A, y: A): A;
public static getMempty<A extends Monoid<A>>(instance: A): Monoid<A> { // Generalized operations
return instance.getMempty();
}
public static mappend<A>(instance: Monoid<A>, x: A, y: A): A; // support for primitive type
public static mappend<A extends Monoid<A>>(instance: A, y: A): Monoid<A>; // support for reference type
public static mappend<A, B extends Monoid<B>>(instance: Monoid<A> | B, y: A | B, z?: A): A | Monoid<B> {
if (typeof z === 'undefined') return (instance as B).mappend(instance as B, y as B);
else return (instance as Monoid<A>).mappend(y as A, z);
}
}
abstract class List<A> extends Monoid<List<A>> {
public getMempty<A>(): Nil<A> {
return new Nil;
}
public mappend(xs: List<A>, ys: List<A>): List<A> {
if (xs instanceof Cons) return new Cons(xs.value, Monoid.mappend(xs.next, ys));
return ys;
}
}
class Nil<A> extends List<A> {}
class Cons<A> extends List<A> {
public constructor(public readonly value: A, public readonly next: List<A>) {
super();
}
}
Who does this impact? Who is this for?
This proposal is intended to help all users that uses this library.
Describe alternatives you've considered
I'll add alternatives tomorrow, I'm so tired now.
Additional context
Actually, this proposal has some issues that I want to have conversation about:
how can we simplify function overloading like mappend's one?
constructors are not good to compose. Is it good to add accessor property that retrieves normal function form of constructor to classes that express value constructor?
how can we use instanceof type guard well? it doesn't work well in some cases.
When ad-hoc polymorphic function takes over two value which we may infer type class instance from, how can we determine what we should use?
Is it good to add class which abstracts classes that express ADT and TypeClass(furthermore, ADT that supports inference based over its value)?
How can we support implementing type class instances? should we use mixin for multiple inheritance?
Your environment
Software
Version(s)
TypeScript
3.6.2
The text was updated successfully, but these errors were encountered:
ENvironmentSet
changed the title
Proposal: Using classes to defining Type Class & ADT
Proposal: Using classes to define Type Class & ADT
Oct 24, 2019
🚀 Feature request
Current Behavior
Currently, we define ADT by using interfaces, type synonyms, union type and normal function:
Desired Behavior
So redundant. Definitions are spread out over source code.
And, current way of simulating ad-hoc polymorphisms with type class instance is really, really verbose to use(We must give type class instance definition to ad-hoc polymorphic function every time we call them).
Suggested Solution
Why don't we use classes? class combines definitions into one. also, we can easily infer type class instance from value when we use classes for defining ADT.
Here is my solution:
Who does this impact? Who is this for?
This proposal is intended to help all users that uses this library.
Describe alternatives you've considered
I'll add alternatives tomorrow, I'm so tired now.
Additional context
Actually, this proposal has some issues that I want to have conversation about:
mappend
's one?instanceof
type guard well? it doesn't work well in some cases.Your environment
The text was updated successfully, but these errors were encountered: