Fp-ts: Document C, T and V

Created on 28 Feb 2019  路  10Comments  路  Source: gcanti/fp-ts

Love the new docs! It would be great if they could explain:

  • what a C suffix means, e.g. Alt2C vs Alt2
  • what a T suffix means, e.g. sequenceT
  • what a v suffix means, e.g. foldable2v

I think I'm right in saying sequenceT means "sequence tuple", but there's also EitherT which is "Either Transformer" right? I'm not clear on the C or v suffixes.

Most helpful comment

what a v suffix means, e.g. foldable2v

@leemhenson 2v means "second version" and @giogonzo explained it well

"All the 2v methods and types are breaking alternatives for @deprecated methods"

what a C suffix means, e.g. Alt2C vs Alt2

The naming convention is:

  • the number means the kind
  • C means Curried

| Kind | Type class | Type defunctionalization | Note |
| ------------------ | -------------------- | ------------------------ | ------------------------------------------------------- |
| all | Functor<F> | HKT<F, A> | |
| * -> * | Functor1<F> | Type<F, A> | |
| * -> * -> * | Functor2<F> | Type2<F, L, A> | |
| * -> * -> * | Functor2C<F, L> | Type2<F, L, A> | A variant of Functor2 where L is fixed |
| * -> * -> * -> * | Functor3<F> | Type3<F, U, L, A> | |
| * -> * -> * -> * | Functor3C<F, U, L> | Type3<F, U, L, A> | A variant of Functor3 where both U and L is fixed |

Example Functor

The base definition

export interface Functor<F> {
  readonly URI: F
  readonly map: <A, B>(fa: HKT<F, A>, f: (a: A) => B) => HKT<F, B>
}

The defintion for type constructors of kind * -> * -> * (e.g. Either)

export interface Functor2<F extends URIS2> {
  readonly URI: F
  //             v-- here L is free
  readonly map: <L, A, B>(fa: Type2<F, L, A>, f: (a: A) => B) => Type2<F, L, B>
}

The defintion for type constructors that start with kind * -> * -> * but need to be constrained in order to admit an instance (e.g. Validation).

//                           this fixes L --v
export interface Functor2C<F extends URIS2, L> {
  readonly URI: F
  readonly _L: L
  //                                v-- here L is fixed ---------------v
  readonly map: <A, B>(fa: Type2<F, L, A>, f: (a: A) => B) => Type2<F, L, B>
}

For example, Validation admits a Functor instance only if you provide a Semigroup instance for the failure part

//   this fixes L --v                                   v-- here L is fixed
const getFunctor = <L>(S: Semigroup<L>): Functor2C<"Validation", L> = { ... }

what a T suffix means, e.g. sequenceT

in sequenceT means Tuple, I borrowed the name from the corresponding Haskell function

However usually it means Transformer like in "monad transformers" (e.g. OptionT, EitherT, ReaderT, StateT)

Some of them have been there for a while now, but I guess @gcanti is waiting for some bigger breaking change to release the next major ;)

@giogonzo that's right. Also [email protected] was actually planned for a couple of months ago, but I was waiting for this PR https://github.com/Microsoft/TypeScript/pull/26349.

Alas it has been posponed 2-3 times now.

The PR is contained in the TypeScript 3.4 release (March 2019) so, if it lends, I predict a [email protected] release around April or May.

All 10 comments

+1 documentation needs a lot of love.

I am a fan of the lib but documentation needs examples with usage to make clear the expected functionality.

Also, the approach taken for moving to new syntax is not sound.

For example OptionT is just a mess.
I mean how usable is OptionT2v2C?
why do I have to learn the convention of what T2v2C means?

Just change the interface and provide a migration path.

If people update the version, it will break for them and they will have to migrate.

If you explain the migration path it will be fine.

Edit:
another example:

why would anyone prefer to use
"getOptionT2v" instead of "chain"?
how is the new name better?

If people update the version, it will break for them and they will have to migrate.

All the 2v methods and types are breaking alternatives for @deprecated methods (I actually discovered just a few days ago that tslint will warn for usages of deprecated exports!), I think it's awesome to see a library taking an incremental and clean approach to breaking changes like this.

Some of them have been there for a while now, but I guess @gcanti is waiting for some bigger breaking change to release the next major ;)

I think I'm right in saying sequenceT means "sequence tuple", but there's also EitherT which is "Either Transformer"

Yes the T in sequenceT is quite an exception (I remember also @joshburgess complaining about this)

C stands for "curried" I think, meaning that you can bind additional type parameters in advance and leave out only A for later inference.

what a v suffix means, e.g. foldable2v

@leemhenson 2v means "second version" and @giogonzo explained it well

"All the 2v methods and types are breaking alternatives for @deprecated methods"

what a C suffix means, e.g. Alt2C vs Alt2

The naming convention is:

  • the number means the kind
  • C means Curried

| Kind | Type class | Type defunctionalization | Note |
| ------------------ | -------------------- | ------------------------ | ------------------------------------------------------- |
| all | Functor<F> | HKT<F, A> | |
| * -> * | Functor1<F> | Type<F, A> | |
| * -> * -> * | Functor2<F> | Type2<F, L, A> | |
| * -> * -> * | Functor2C<F, L> | Type2<F, L, A> | A variant of Functor2 where L is fixed |
| * -> * -> * -> * | Functor3<F> | Type3<F, U, L, A> | |
| * -> * -> * -> * | Functor3C<F, U, L> | Type3<F, U, L, A> | A variant of Functor3 where both U and L is fixed |

Example Functor

The base definition

export interface Functor<F> {
  readonly URI: F
  readonly map: <A, B>(fa: HKT<F, A>, f: (a: A) => B) => HKT<F, B>
}

The defintion for type constructors of kind * -> * -> * (e.g. Either)

export interface Functor2<F extends URIS2> {
  readonly URI: F
  //             v-- here L is free
  readonly map: <L, A, B>(fa: Type2<F, L, A>, f: (a: A) => B) => Type2<F, L, B>
}

The defintion for type constructors that start with kind * -> * -> * but need to be constrained in order to admit an instance (e.g. Validation).

//                           this fixes L --v
export interface Functor2C<F extends URIS2, L> {
  readonly URI: F
  readonly _L: L
  //                                v-- here L is fixed ---------------v
  readonly map: <A, B>(fa: Type2<F, L, A>, f: (a: A) => B) => Type2<F, L, B>
}

For example, Validation admits a Functor instance only if you provide a Semigroup instance for the failure part

//   this fixes L --v                                   v-- here L is fixed
const getFunctor = <L>(S: Semigroup<L>): Functor2C<"Validation", L> = { ... }

what a T suffix means, e.g. sequenceT

in sequenceT means Tuple, I borrowed the name from the corresponding Haskell function

However usually it means Transformer like in "monad transformers" (e.g. OptionT, EitherT, ReaderT, StateT)

Some of them have been there for a while now, but I guess @gcanti is waiting for some bigger breaking change to release the next major ;)

@giogonzo that's right. Also [email protected] was actually planned for a couple of months ago, but I was waiting for this PR https://github.com/Microsoft/TypeScript/pull/26349.

Alas it has been posponed 2-3 times now.

The PR is contained in the TypeScript 3.4 release (March 2019) so, if it lends, I predict a [email protected] release around April or May.

Good info, thanks!

@giogonzo I am not against the deprecation mechanism/concept.
But if in order to deprecate a method you need to generate method names that imply state, args, etc then deprecation is the wrong path.

So
"deprecate StrMap.traverseWithKey in favour of strmap.traverseWithIndex"
is great! (btw strmap -lowercase- does not show in the docs for StrMap)
but the rest of the naming choices are not.

Ideally you mark a function deprecated and have the overload(new function) with the new order as the recommended one but use the same/similar name.

If TS/JS doesn't allow the overloading then personally I would go with break/migrate instead of devising method names with versions and encoding in their name.

Also note that eventually the deprecated methods should disappear and a migration path will be then required, leaving you with only 2v methods that will make you question why they exist like that.

As I already said I am a fan of the lib and use it.
But it is hard to promote to others as it is not immediately readable.

People can relate to "chain" as there are a lot of FP concepts everywhere for it.
But "getOptionT2v" is an fp-ts naming concept and I need decoding to understand what is means.

Also, why would a user care if the function is v2 or v1.
And previously there was xxxxT2, so xxxxT2v2C is??? it is confusing...

I know I sound very critical, please do not take my comments in a negative way.

I am trying to provide constructive feedback from a real usage perspective.

And @gcanti BIG THANKS for the great work!

Ideally you mark a function deprecated and have the overload(new function) with the new order as the recommended one but use the same/similar name.

This is not always possible as you sometimes have different constraints, functions curried differently, etc. When possible, this has already been done: "deprecate StrMap.traverseWithKey in favour of strmap.traverseWithIndex"

Also note that eventually the deprecated methods should disappear and a migration path will be then required, leaving you with only 2v methods that will make you question why they exist like that.

I'm pretty sure the plan is to actually switch to the name without 2v, effectively dropping the suffix and removing completely the older/deprecated version in the next major

@giogonzo that's the plan, ideally after the great 2.0 clean up, you will just do some find and replace (assuming you are not using deprecated APIs)

@gkamperis thanks, I appreciate the feedback.

@leemhenson added code-conventions.md

btw strmap -lowercase- does not show in the docs for StrMap

@gkamperis https://gcanti.github.io/fp-ts/StrMap.ts.html#strmap-1

some find and replace

It would be nice to provide a codmod for this, does jscodeshift support TypeScript now?

@gcanti Thanks for the link

I think the problem is that the TOC points to

https://gcanti.github.io/fp-ts/StrMap.ts.html#strmap

instead of the one you linked.

@gkamperis looks like doctoc is not able to handle case sensitive links, fixed by adding a suffix https://gcanti.github.io/fp-ts/modules/StrMap.ts.html#strmap-constant, thanks for pointing out

Was this page helpful?
0 / 5 - 0 ratings

Related issues

FruitieX picture FruitieX  路  3Comments

bioball picture bioball  路  4Comments

steida picture steida  路  4Comments

vicrac picture vicrac  路  4Comments

josete89 picture josete89  路  3Comments