The problem
The current implementation of foldMap has some type inference issues
import * as option from 'fp-ts/lib/Option'
import * as array from 'fp-ts/lib/Array'
import { monoidSum } from 'fp-ts/lib/Monoid'
import { foldMap } from 'fp-ts/lib/Foldable'
const monoid = option.getStaticMonoid(monoidSum)
const as = [1]
// x1 :: Option<{}> // <= {} instead of number
const x1 = foldMap(array, monoid, a => option.some(a), as)
Here TypeScript infers {} instead of number!
The solution
If I curry foldMap, the result is way better
export function foldMap$<F extends HKTS, M>(foldable: StaticFoldable<F>, monoid: StaticMonoid<M>): <A>(f: (a: A) => M, fa: HKT<A>[F]) => M {
return <A>(f: (a: A) => M, fa: HKT<A>[F]) => foldable.reduce((acc, x: A) => monoid.concat(f(x), acc), monoid.empty(), fa)
}
// x2 :: Option<number>
const x2 = foldMap$(array, monoid)(a => option.some(a), as)
The pattern
After some trials and errors, a clean pattern seems to emerge: whenever in PureScript there is a type constraint, in fp-ts we need a curried function accepting the static dictionaries as first arguments
PureScript
foldMap :: forall f a m. Foldable f, Monoid m => (a -> m) -> f a -> m
TypeScript
function foldMap<F extends HKTS, M>(foldable: StaticFoldable<F>, monoid: StaticMonoid<M>): <A>(f: (a: A) => M, fa: HKT<A>[F]) => M
This is good news: in general porting PureScript libraries to fp-ts is pretty straightforward (with the possible exception of highly polymorphic signatures)
Alas there are many functions in fp-ts which I wrote when I was still learning TypeScript in February/March and before I was aware of this pattern, for example
I'd like to change the current implementation but it's obviously a breaking change. I see 2 options
An example of (2) would be to define a curried foldMap$ as above and just deprecate foldMap. New code should use foldMap$ instead of foldMap so it will almost ready for the upgrade to v0.3 (should be a simple replace). Not sure if it worth it though
A Con of (2) is a more confusing code base, a Pro is that it leaves some time to figure out if there will be other breaking changes affecting other parts of fp-ts.
@OliverJAsh @sledorze @danielepolencic @leemhenson sorry to tag you all but being "real world" users I'd love to hear from you what you think
I'm fine with (1). It's still early days and I don't mind the breaking changes.
Also, I'll take the opportunity to ask a question.
If we decide for:
(1) brutal braking changes releasing v0.3
Is there anything like https://github.com/facebook/jscodeshift for Typescript?
Breaking changes is ok with me.
... leaves some time to figure out if there will be other breaking changes affecting other parts of fp-ts.
Maybe leave 0.3 in pre for a while until this is bottomed out though?
Is there anything like https://github.com/facebook/jscodeshift for Typescript?
That would be great, AFAIK there's no such a tool. Perhaps it will be available after the work on prettier and typescript-eslint-parser is settled down
PR here https://github.com/gcanti/fp-ts/pull/93
Maybe leave 0.3 in pre for a while until this is bottomed out though?
I will publish a version in the next channel (npm install fp-ts@next) so we can check that everything is ok before actually releasing
@gcanti breaking changes fine with me too!
Relevant https://github.com/gcanti/fp-ts/pull/93#issuecomment-303172449
Hi all, I put up a branch (dev) with the lib folder committed in, please give it a spin on your codebase / lib and let me know if there are unexpected issues
npm i gcanti/fp-ts#dev
Pre-released v0.3 as fp-ts@next
FYI here's the change log so far
# 0.3.0
- **New Feature**
- add `StateT` monad transformer, closes #104 (@gcanti)
- add `Store` comonad, closes #100 (@rilut)
- add `Last` monoid, closes #99 (@gcanti)
- add `Id` monad (@gcanti)
- Array: add extend instance (@gcanti)
- NonEmptyArray: add comonad instance (@gcanti)
- `examples` folder
- `exercises` folder
- **Polish**
- Tuple: remove StaticFunctor checking (@rilut)
- **Breaking Change** (@gcanti)
- required typescript version: **2.3.3**
- drop `Static` prefix in type classes
- Change contramap signature, closes #32
- Validation: remove deprecated functions
- Foldable/toArray
- Dictionary/fromFoldable
- Dictionary/toUnfoldable
- Profunctor/lmap
- Profunctor/rmap
- Unfoldable/replicate
- compositions: renaming and signature changes
- `getFunctorComposition` -> `getCompositionFunctor`
- `getApplicativeComposition` -> `getCompositionApplicative`
- `getFoldableComposition` -> `getCompositionFoldable`
- `getTraversableComposition` -> `getCompositionTraversable`
- `OptionT`, `EitherT`, `ReaderT` refactoring
- drop `IxMonadT`, move `IxIO` to the `examples` folder
- drop `Trans` module
- `Free` refactoring
- drop `rxjs` dependency
- drop `lib-jsnext` folder
- make `None` constructor private
- remove `Pointed` and `Copointed` type classes