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.
Wow, this looks great! 😍
I'm having trouble understanding how the Reader monad can help in more complex examples though.
Take a look at this for instance: (functions with the "2" suffix are the ones that I would write having dependencies as the first parameter)
f needs to make b explicit even if could be implicit (like it is in f2)
all the functions in the g pipe need to take the result from the previous computation and pass it as the first parameter to the transform functions, while this is implicit in g2. This leads to less readable code and harder composition. Is there something I'm missing?
Is it generally right to merge all the dependencies of the functions used by g like I did with Dependencies & OtherDependencies?
I know this is an older post, I'm having trouble understanding how this fixes the original issue.
As you can see, h and g must have knowledge about f dependencies despite not using them.
That's true after the refactor as well. Dependencies of f are part of g and h signatures. The way the example is written, the problem is compounded when g has a dependency, because now f depends on parameters of g as well. They could be distinct types, but dependencies of g must be a superset of dependencies of f, e.g.
I understand the desire to curry them so that we can pipe things together, but we haven't lessened the pain of refactoring here at all.
Even if g did not directly call f but was instead piped to it, would it not be better suited to have a flavor of flow or pipe that would automatically coalesce the dependencies?
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 . fresult is a function withdepsargumentFor 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
gs are equivalent (so feel free to choose the style you prefer)I'm used to put deps as the first argument since this lets you partially apply f:
const f = (deps: Dependencies) => (b: boolean): string => (...)
Yes the whole idea has a lot of sense, and I mean adding argument after not before. Thanks for clarifying!
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.
Wow, this looks great! 😍
I'm having trouble understanding how the Reader monad can help in more complex examples though.
Take a look at this for instance: (functions with the "2" suffix are the ones that I would write having dependencies as the first parameter)
In particular, notice how:
fneeds to makebexplicit even if could be implicit (like it is inf2)gpipe need to take the result from the previous computation and pass it as the first parameter to the transform functions, while this is implicit ing2. This leads to less readable code and harder composition. Is there something I'm missing?glike I did withDependencies & OtherDependencies?That's exactly what I needed. I saw you just released
chainWin 2.6.0. Great job thanks! :)Do we have a standard name for
(r: Reader<R,A>) => A?Yoneda?
Provider<R>is isomorphic toRWhoops, my brain is starting to melt, but I like all of this. :)
Wait, wait, I get it now
I know this is an older post, I'm having trouble understanding how this fixes the original issue.
That's true after the refactor as well. Dependencies of
fare part ofgandhsignatures. The way the example is written, the problem is compounded whenghas a dependency, because nowfdepends on parameters ofgas well. They could be distinct types, but dependencies ofgmust be a superset of dependencies off, e.g.I understand the desire to curry them so that we can pipe things together, but we haven't lessened the pain of refactoring here at all.
Even if
gdid not directly callfbut was instead piped to it, would it not be better suited to have a flavor offloworpipethat would automatically coalesce the dependencies?Great article!
I'd love to see another article about Writer using fp-ts.