Fp-ts: Composing and piping for Records

Created on 26 Oct 2018  Â·  5Comments  Â·  Source: gcanti/fp-ts

Question

Hey @gcanti ,

Got a quick one related to pipe and compose for Records.
Most of the methods from records follow, object first convention, like in lodash, i.e., traverserWithKey(option)(X, Y), where X is an object and Y is a function.
It makes piping and composing not possible, so in result there is no chance to make clean pointfree bigger computation since objects sits in the middle.

I was trying to flip these functions, but flip requires currying and after flipping & currying I got type checks errors and I’m not able to recreate type.

What would be awesome to have
js import * as R from ‘fp-ts/lib/Record’ const computation = pipe( R.traverseWithKey(option)((val, key) => …), R.map(val => …) // …etc ) computation(someRecord)

If I’m missing something, please let me know as I don’t want to use ramda and only option which I see right now, is to go with fromFoldable and toArray, but then, I'm switching type and I'd like to avoid such conversion.

Many thanks,
Damian

Which versions of fp-ts, and which browser and OS are affected by this issue? Did this work in previous versions of fp-ts?
"fp-ts": "^1.10.0"

All 5 comments

@damianbaar before 1.0 fp-ts was more like rambda the problem is that typescript resolves types from "left to right" which makes the usage of a library hard that has the type given argument as last parameter. That is why @gcanti decided to move the type given parameter back to the left of the signature. You can still curry and flip by yourself but have to add all type information by yourself. The type can not be infered anymore by the compiler.

Also pipe (and flip, curry, etc...) doesn't play well with polymorphic functions

const of = <A>(a: A): Array<A> => [a]
const map = <A, B>(f: (a: A) => B) => (as: Array<A>): Array<B> => as.map(f)
const len = (s: string): number => s.length

const computation = pipe(
  of,
  map(len) // doesn't type-check
)

Hey, thanks guys for the answers. I realised that I can rewrite it a bit differently and I went with option, and fromNullable and I believe it becomes more readable and better than piping, however got some extra questions,

1) would it be possible to attach key as second argument to all record functions where Object.keys is already called, like filter, filterMap, partition - sometimes I do have a need to do some work based on key not only the value.

2) is there any construction available to have Kleisli compositions? if so, is it safe for piping and currying?

3) when chaining couple of options and making concatenation latter on, I have to do something like, concat(a, concat(b, c)) is there any chance to make concat variadic? I see the foldablev2 and getFoldableComposition that there is a chance to call reduce with concat, but not sure why concat is not variadic in first place.

That is why @gcanti decided to move the type given parameter back to the left of the signature.

but if function would be curried then we can specify last argument upfront and avoid this limitation? like R.traverseWithKey(option)<T>((val: T[K], key: K extends keyof T) => …)(someObj)

would it be possible to attach key as second argument

we could add *WithKey variants (like map/mapWithKey and traverse/traverseWithKey).

We could also add some new related type classes

  • FunctorWithIndex (https://pursuit.purescript.org/packages/purescript-foldable-traversable/3.4.0/docs/Data.FunctorWithIndex)
  • FoldableWithIndex (https://pursuit.purescript.org/packages/purescript-foldable-traversable/3.4.0/docs/Data.FoldableWithIndex)
  • TraversableWithIndex (https://pursuit.purescript.org/packages/purescript-foldable-traversable/3.4.0/docs/Data.TraversableWithIndex)
  • FilterableWithIndex ??? (missing in purescript-filterable)

is there any construction available to have Kleisli compositions?

No (I'm afraid that kleisli composition would suffer the same issues of compose / pipe), you may want to do a rewrite using chain

declare const g: (a: string) => Option<number>
declare const f: (b: number) => Option<boolean>

const h = (a: string) => g(a).chain(f)

is there any chance to make concat variadic?

No but you can use fold (from Semigroup or Monoid) for that

but if function would be curried then we can specify last argument upfront

You MUST rather than you can, it would be awkward.

With TypeScript point-free style is a lost cause (for now), therefore this library is optimized otherwise.

sounds great, thanks for all the answers. Cheers.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

miguelferraro picture miguelferraro  Â·  3Comments

mattgrande picture mattgrande  Â·  3Comments

Crashthatch picture Crashthatch  Â·  4Comments

mustafaekim picture mustafaekim  Â·  4Comments

maciejsikora picture maciejsikora  Â·  3Comments