I am Software Developer, currently interested in static type languages (TypeScript, Elm, ReScript) mostly in the frontend land, but working actively in Python also. I am available for mentoring.
Very nice functional concept. But I have small concern if the whole typing of that has/or not a big sense. I mean we really use here a HOF and the whole composition h . g . f result is a function with deps argument
For the second, I see some benefit, but not see doing it like below as a bad thing (yes deps are passed explicitly, but is it any issue?)
constf=(b:boolean)=>(deps:Dependencies)=>(b?deps.i18n.true:deps.i18n.false)constg=(n:number)=>(deps:Dependencies)=>f(n>deps.lowerBound)(deps)// above explicit deps which we can useconsth=(s:string)=>g(s.length+1)
Not get me wrong, just thinking if the whole additional piping and typing is beneficial here.
I have small concern if the whole typing of that has/or not a big sense
Well, you are just writing a bunch of functions returning Reader, whether or not you add an explicit type. The point is making the dependencies as implicit as possibile, the key is to put them as a last argument. Note that often people put the dependencies as a first argument
I am Software Developer, currently interested in static type languages (TypeScript, Elm, ReScript) mostly in the frontend land, but working actively in Python also. I am available for mentoring.
I'd say there'e no magic in here - in FP all functions have to be referentially transparent at the end of the day i.e. all arguments have to be passed directly! What I think is crucial in here is the conceptual "turning inside-out" (or rather "bottom-up", should I say) - instead of passing props/arguments down multiple levels, we pass a function consuming these props (Reader) multiple levels up, in an almost implicit way. When the Reader reaches "the surface", we can pass its dependencies directly.
I am Software Developer, currently interested in static type languages (TypeScript, Elm, ReScript) mostly in the frontend land, but working actively in Python also. I am available for mentoring.
Yes I see this in that way also. The whole idea here is in dependency argument in the end and not in the beginning.
In my comment I was more addressing the whole additional idealogy over that, like special typings and using some pipe, ask, chain. I see these as only a fog and complexity over really simple but powerful concept.
result and pointFreeVersion must be refactored as well, fortunately you can use ReaderEither's monadic interface
// before constresult=pipe(E.right('foo'),E.chain(f),E.map(g),E.chain(h))constpointFreeVersion=flow(f,E.map(g),E.chain(h))// afterconstresult=pipe(RE.right('foo'),RE.chain(f),RE.map(g),RE.chain(b=>RE.fromEither(h(b))))constpointFreeVersion=flow(f,RE.map(g),RE.chain(b=>RE.fromEither(h(b))))
There's a benefit in using the monadic interface though: software is written in a uniform style, regardless of the effect.
I was just about to say it: I think main benefit is (ironically) readability - by saying explicitly Reader<Dependencies, string> you clearly communicate your intent (assuming others know the concept as well, of course 😄).
Very nice functional concept. But I have small concern if the whole typing of that has/or not a big sense. I mean we really use here a HOF and the whole composition
h . g . f
result is a function withdeps
argumentFor the second, I see some benefit, but not see doing it like below as a bad thing (yes deps are passed explicitly, but is it any issue?)
Not get me wrong, just thinking if the whole additional piping and typing is beneficial here.
Well, you are just writing a bunch of functions returning
Reader
, whether or not you add an explicit type. The point is making the dependencies as implicit as possibile, the key is to put them as a last argument. Note that often people put the dependencies as a first argumentmaking composition more difficult.
all the following
g
s are equivalent (so feel free to choose the style you prefer)Yes the whole idea has a lot of sense, and I mean adding argument after not before. Thanks for clarifying!
I'm used to put deps as the first argument since this lets you partially apply f:
const f = (deps: Dependencies) => (b: boolean): string => (...)
I'd say there'e no magic in here - in FP all functions have to be referentially transparent at the end of the day i.e. all arguments have to be passed directly! What I think is crucial in here is the conceptual "turning inside-out" (or rather "bottom-up", should I say) - instead of passing props/arguments down multiple levels, we pass a function consuming these props (
Reader
) multiple levels up, in an almost implicit way. When the Reader reaches "the surface", we can pass its dependencies directly.Yes I see this in that way also. The whole idea here is in dependency argument in the end and not in the beginning.
In my comment I was more addressing the whole additional idealogy over that, like special typings and using some pipe, ask, chain. I see these as only a fog and complexity over really simple but powerful concept.
There's a benefit in using the monadic interface though: software is written in a uniform style, regardless of the effect.
You can think of
Reader
as an effect, muck likeEither
orTask
.Let's say you have the following snippet
and at some point you must refactor
f
toresult
andpointFreeVersion
must be refactored as well, fortunately you can useReaderEither
's monadic interfaceI was just about to say it: I think main benefit is (ironically) readability - by saying explicitly
Reader<Dependencies, string>
you clearly communicate your intent (assuming others know the concept as well, of course 😄).That's right, you write programs by composing kleisli arrows
A -> M<B>
, for some effectM
.So
Reader
(orReaderEither
,ReaderTaskEither
,Option
,Either
, etc...) is just one of the possible effects