-
Notifications
You must be signed in to change notification settings - Fork 376
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add typescript supports #140
Comments
If you can type |
@joneshf Functor: |
Oh... This is illegal typescript code, but I wanted. interface Apply<(t: T) => U> {
ap(u: U): U;
}
interface Apply<T> {
} However, a.ap(f); // a :: A<T>, f :: A<(T => U)>, a.ap(f) :: A<U> or A.ap(a, f); // a :: A<T>, f :: A<T => U>, A.ap(a, f) :: A<U> In this cases, the typescript types are: interface Apply<T> {
ap<U>(f: Apply<(t: T) => U>): U;
} or interface Apply<T> {
ap(a: T, f: Apply<(t: T) => U>): Apply<U>;
}
interface ApplyStatic<T, U> {
new(...args: any[]): Apply<any>;
ap(a: Apply<T>, f: Apply<(t: T) => U>): Apply<U>;
} Maybe and Either of TsMonad are not supported Apply and Applicative. The reason may be this problem... |
How do you do a natural transformation in typescript as well or high order On Wed, 11 May 2016, 20:31 Mizunashi Mana, notifications@github.com wrote:
|
I understood we cannot natural transforming in typescript. TypeScript has some problems on type system. However, I think we can provide main support (Monad/Monoid/Traversal). NotesIn TypeScript: const m = (Functor<A>)Identity(new A());
m.equals(a => Identity(new A()); // this will be compile error But, this will be ok: interface Functor<T> {
map<U>(f: (t: T) => U): Functor<U>;
}
interface Eq<T> {
equals(t: T): boolean;
}
class A<T> implements Functor<T>, Eq<A<T>> {
map<U>(f: (t: T) => U): A<U> { return new A(); }
equals(a: A<T>): boolean { return true; }
}
new A().map(a => a).equals(new A()); So, that cases, we cannot: function fmap<T, U>(f: (t: T) => U): (g: Functor<T>) => Functor<U> {
return a => a.map(f);
}
fmap(a => a)(new A()).equals(new A()); // compile error In this cases, TypeScript user force to cast types... |
You've just shown why the typescript support is pointless from my point of view, by all the notes and changes you've suggested that are required. I just think the typescript system is too restrictive, by not being free enough (oxymoron considering we're talking about JavaScript). 👎 from me |
Ok, I considered deeply, I'm sorry for taking your time 🙇 . |
Please note, the issue wasn't about your proposal, but about the fact that TypeScript is limited by its very nature. Therefore the gains/rewards that we get from it are limited and may even restrict the future additions to the specification. Having said all of this, there isn't anything stopping you from making the repo hosted somewhere else though, if you do get a benefit from having the TypeScript definitions. |
@SimonRichardson So, I stop declaring TypeScript types. |
Tell me if I'm wrong here (since I don't know typescript that in-depth), but that doesn't seem to describe export class Maybe<T> implements Monad<T>, Functor<boolean>, Eq<Maybe<T>> { |
@joneshf However, class Maybe<T> {
fmap<U>(f: (t: T) => U): Maybe<U> { ... }
} this one can be Functor, cannot? The TsMonad Functor interface can be a helper for declare type. class Maybe<T> implements Functor<boolean> {
fmap<U>(f: (t: T) => U): Maybe<U> { ... }
/* fmap(f: (t: boolean) => boolean): Maybe<T> { ... } // can define */
/* fmap<U>(f: (t: boolean) => U): Maybe<U> { ... } // also can define... */
} Actually, I'm usual using |
Sorry, I wasn't very clear. The last example is what I meant. class Maybe<T> implements Functor<boolean> {
fmap<U>(f: (t: boolean) => U): Maybe<U> { ... }
} That's not a But you're right, the first example is a class Maybe<T> {
fmap<U>(f: (t: T) => U): Maybe<U> { ... }
} You can define them inline to a class, you just can't abstract out the interface with typescript. |
@joneshf function void<T extends Functor<U>, U, R extends Functor<{}>>(fa: T): R {
return fa.fmap(a => ({}));
} That type signature passed that: function void<T extends Functor<U>, U, R extends Functor<{}>>(fa: T): R {
return Maybe.Just({});
} I understood that TsMonad's Functor interface is wrong for that cases. |
I tried to make an attempt at this (not having looked at TsMonad) with my limited understanding of these types, and within the limitations of TS interfaces (no static methods, no multiple extending). interface Setoid<T> {
equals(b: Setoid<T>): boolean;
}
interface Semigroup<T> {
concat(b: Semigroup<T>): Semigroup<T>;
}
interface Monoid<T> extends Semigroup<T> {
/* static */ empty<T>(): Monoid<T>;
}
interface Functor<T> {
map<U>(fn: (t: T) => U): Functor<U>;
}
interface Apply<T> extends Functor<T> {
apply<U>(fn: Apply<(t: T) => U>): Apply<U>;
}
interface Applicative<T> extends Apply<T> {
/* static */ of<U>(a: U): Applicative<U>;
}
interface Alt<T> extends Functor<T> {
alt(b: T): Alt<T>;
}
interface Plus<T> extends Alt<T> {
/* static */ zero<T>(): Plus<T>;
}
interface Alternative<T> extends Plus<T>, Applicative<T> {
}
interface Foldable<T> {
reduce<U>(fn: (u: U, t: T) => U, u: U): U;
}
interface Traversable<T> extends Functor<T>, Foldable<T> {
traverse<U, V>(fn: (t: T) => Applicative<U>, of: (v: V) => Applicative<V>): Applicative<Traversable<U>>;
}
interface Chain<T> extends Apply<T> {
chain<U>(fn: (t: T) => Chain<U>): Chain<U>;
}
interface ChainRec<T> extends Chain<T> {
/* static */ chainRec<A,B,C>(f: (next: (a: A) => C, done: (b: B) => C, value: A) => ChainRec<C>, i: A): ChainRec<B>;
}
interface Monad<T> extends Applicative<T>, Chain<T> {
}
interface Extend<T> {
extend<U>(f: (v: Extend<T>) => U): Extend<U>;
}
interface Comonad<T> extends Functor<T>, Extend<T> {
extract<U>(): U; // 'same U as in extend's f -- how to bind?
}
interface Bifunctor<T,U> extends Functor<T> /*, Functor<U>*/ {
bimap<B,D>(f: (v: T) => B, g: (v: U) => D): Bifunctor<B,D>;
}
interface Profunctor<T,U> extends Functor<T> /*, Functor<U>*/ {
promap<B,D>(f: (v: T) => B, g: (v: U) => D): Profunctor<B,D>;
} I've likely made mistakes, but I hope this might be useful. |
@tycho01 The problem with these is that some of them actually don't work. I've tried similar interface definitions and found that they're not as good as they seem. Consider your Functor interface:
This says that We can't write a proper Functor interface since TypeScript lacks higher kinded types. I have run into similair problems in my library Jabz. The best solution I've come of with is to create a |
@paldepind: If I understand correctly, the point here is that even if you have a I tried to see if I could make a quick reproduction of the issue you were explaining about, presuming I understand it correctly. I'm trying the following: interface Functor<T> {
map<U>(fn: (t: T) => U): Functor<U>;
}
class MyFunctor<T> implements Functor<T> {
constructor(public val: T) {};
map<U>(fn: (t: T) => U): MyFunctor<U> {
return new MyFunctor(fn(this.val));
}
}
let strFtor = new MyFunctor('hi');
let numFtor = strFtor.map(s => s.length);
// ^ inferred to be a MyFunctor<number>, as expected Would you mind explaining a bit further? |
There could be a possibility in using a different encoding for HKT as seen in Java or similar. I did try and encode this sort of thing into Haxe, but I ended up having to cast at some point because of the issues with the type system. I've not used typescript so don't know to what extent any of this is possible. |
@tycho01 how does it work for chain, considering you don't return |
@SimonRichardson: Thank you; with a similar attempt at @mizunashi-mana, I think the problem in the |
@SimonRichardson: I guess you were already on the right path here, but I've been corrected in that thread on needing support for HKT rather than nominal typing. |
@tycho01 It's actually support for higher-kinded polymorphism. Typescript already has HKTs (i.e. generics) |
@rjmk Typescript doesn't have HKTs, i.e. you can't have a type parametrized by a parametrized type. There is an open issue tracking this. |
@masaeedu I was drawing a distinction between type constructors/parameterised types (functions from types to either a type or a type constructor) vs functions from type constructors to types/type constructors. Since I made that comment, I've discovered not everyone makes the distinction with that terminology |
I think that I may have figured out how to encode interface Functor<Tag extends string, T> {
tag: Tag; // A tag unique to the functor
value: any; // Holds the actual data.
fmap<U>(f: (x: T) => U): Functor<Tag, U>;
}
class ArrayWrapper<T> implements Functor<"ArrayWrapper", T> {
tag: "ArrayWrapper";
readonly value: Array<T>;
constructor(elements: Array<T>) {
this.value = elements;
}
fmap<U>(f: (x: T) => U): ArrayWrapper<U> {
return new ArrayWrapper<U>(this.value.map(f));
}
}
class Maybe<T> implements Functor<"Maybe", T> {
tag: "Maybe";
readonly value: T | null;
constructor(newValue: T | null) {
this.value = newValue;
}
fmap<U>(f: (x: T) => U): Maybe<U> {
return this.value === null
? new Maybe<U>(null)
: new Maybe(f(this.value));
}
}
function f<Tag extends string, T>(x: Functor<Tag, T>) {
return x.fmap((x: T) => true);
}
const x = new ArrayWrapper([1]);
// This typechecks.
const doesTypecheck: ArrayWrapper<boolean> = f(x)
// You can't assign functors to other functors, even when they share parameters.
const doesNotTypecheck: Maybe<boolean> = f(x); |
@TJSomething: Interesting! Comments:
If we would be able to properly type the ADTs (I haven't retried I'd be inclined to think this could be beneficial for the standardization process: if you type your library implementing some ADT instances, and it type-checks with the interfaces, you're probably in proper compliance with the spec. |
@TJSomething I used the same technique in fp-ts, though after the 2.4.1 release I'm afraid I have to rewrite the lib from the ground up gcanti/fp-ts#138 (comment) |
Suggestions
Notes
TypeScript can add types without any binding codes. So, we can support TypeScript just to write type definition codes.
TypeScript manage definitions on main definitions repository, DefinitelyTyped.
Already, some definitions of library supporting fantasy land (parsimmon, tsmonad, etc.) were added.
However, the types of each library were defined by some contributors and has some differences...
I would like you to define TypeScript type signatures of fantasy land for TypeScript and fantasy land user.
That has good influences for us.
Thanks!
The text was updated successfully, but these errors were encountered: