For peace of mind, I would love to know whether nested pipes are ok or not.
export const deleteContent: Endomorphism<StateWithSelection> = state =>
pipe(
state,
// state.element
elementLens.modify(
pipe(
state.selection,
mapSelectionToRange,
deleteContentElement,
),
),
select(collapseSelectionToStart(state.selection)),
);
This looks weird as well. It is idiomatic fp-ts code or not?
export const select = (selection: Selection): Endomorphism<Value> => value =>
pipe(
value.selection,
exists(s => eqSelection.equals(s, selection)),
)
? value
: { ...value, selection: some(selection) };
I am writing this question here in order to improve docs. I will send PR once I will understand it.
I am pretty sure I am doing something wrong. But what?
export const setText = (
text: string,
selection?: Selection,
): Endomorphism<Value> => value =>
pipe(
fromNullable(selection),
chain(() => value.selection),
fold(
() => value,
selection =>
pipe(
value,
elementLens.modify(setTextElement(text, selection)),
),
),
);
How to kill this pyramid of doom?
export const deleteContent: Endomorphism<Value> = value =>
pipe(
value.selection,
fold(
() => value,
selection =>
pipe(
value,
elementLens.modify(
pipe(
selection,
mapSelectionToRange,
deleteContentElement,
),
),
select(collapseSelectionToStart(selection)),
),
),
);
If I'm not mistaken, setText and deleteContent can be refactored by removing the fold and replacing it with a map and then getOrElse
export const setText = (
text: string,
selection?: Selection,
): Endomorphism<Value> => value =>
pipe(
fromNullable(selection),
chain(() => value.selection),
map(selection =>
pipe(
value,
elementLens.modify(setTextElement(text, selection)),
)),
getOrElse(() => value)
);
Anyway, you still need the other pipes. In order to improve the readability and expressiveness of the code you can extract some of the "nested" logic into functions.
const modifyElementText = (text: string, value: Value) => (s: Selection): Selection =>
pipe(
value,
elementLens.modify(setTextElement(text, selection)),
)
export const setText = (
text: string,
selection?: Selection,
): Endomorphism<Value> => value =>
pipe(
fromNullable(selection),
chain(() => value.selection),
map(modifyElementText(text, value)),
getOrElse(() => value)
);
Note that:
a => pipe(a, ...)
is the same as:
flow(...)
The rule of thumb is that if a can be inferred, you can probably substitute pipe for flow.
@pfgray Well, I wouldn't agree with that rule of thumb. IMO it bloats API and increases maintenance complexity. If you ever need to get access to hidden argument (for example to parametrise some operator in the flow) you end either adding extra lambdas or rewriting flow to pipe. This in turn leads to a messy code filled with a mix of flow and pipe.
On the other hand after migration to classless/pipeable an idiomatic and universal way to work with fp-ts is to use pipe.
We've been battle-testing fp-ts since 0.x with different teams on different projects and API surface has always been a problem for us in terms of documentation, best practices, idiomatic approaches etc. Therefore I would recommend to always stick to pipe because it's universal and to use flow if _and only if_ you know what you are doing and have strong pros for it besides point-free and code size.
I got it. Thank you for the answers.
Most helpful comment
@pfgray Well, I wouldn't agree with that rule of thumb. IMO it bloats API and increases maintenance complexity. If you ever need to get access to hidden argument (for example to parametrise some operator in the
flow) you end either adding extra lambdas or rewritingflowtopipe. This in turn leads to a messy code filled with a mix offlowandpipe.On the other hand after migration to classless/pipeable an idiomatic and universal way to work with
fp-tsis to usepipe.We've been battle-testing
fp-tssince0.xwith different teams on different projects and API surface has always been a problem for us in terms of documentation, best practices, idiomatic approaches etc. Therefore I would recommend to always stick topipebecause it's universal and to useflowif _and only if_ you know what you are doing and have strong pros for it besides point-free and code size.