These are chat archives for ramda/ramda

22nd
Jul 2017
James
@aretecode
Jul 22 2017 10:13
curious about the use of Array.prototype.slice.call for example, here https://github.com/ramda/ramda/blob/master/src/reverse.js#L31
why use the full proto call directly when there is an example right in invoker using slice? https://github.com/ramda/ramda/blob/master/src/invoker.js
is there a huge perf diff? inlined many times quicker? any issues on it to read?
Kurt Milam
@kurtmilam
Jul 22 2017 11:10
I believe there's a general desire to avoid internal dependencies as much as possible.
James
@aretecode
Jul 22 2017 11:12
internal utilities?
what would the reasoning behind that be?
Kurt Milam
@kurtmilam
Jul 22 2017 11:21
One reason is to make the bundle smaller for those who important individual functions.
If you don't use invoker, but you import another function that relies on it unnecessarily, it'll end up in your import, making your application bundle larger.
And if invoker relied on several other internal functions, you'd end up downloading those, as well, even if you didn't use them in your application. In a worst case scenario, you might explicitly import a single Ramda function and get the whole library.
There's probably also a slight advantage to using the native options whenever possible.
Kurt Milam
@kurtmilam
Jul 22 2017 11:27
Auto currying doesn't come for free, so why use an auto curried internal function where an uncurried native function will do?
Slight performance advantage, that is.
James
@aretecode
Jul 22 2017 11:34
When the currying function is hot because it's used enough, it has the same ability to be inlined as any native function in v8
Kurt Milam
@kurtmilam
Jul 22 2017 11:36
Benchmarks I and others have run suggest that auto currying comes with a cost
The caveat is that benchmarks can't always be believed.
James
@aretecode
Jul 22 2017 11:37
If you're building for custom builds, files that export either the curried function or native depending on usage are possible too
Definitely benchmarks are to be taken with a grain of salt, or a few :-P
Kurt Milam
@kurtmilam
Jul 22 2017 11:38
There are also different ways to Curry a function, and it's possible that the various engines will or have implemented improvements to the way they handle curried functions.
James
@aretecode
Jul 22 2017 11:38
All the same, almost every function in ramda is curried, and 1234 arities have optimized versions
Syaiful Bahri
@syaiful6
Jul 22 2017 11:39
i think it just to short the code, the slice part just want to copy the array, the goal is to call reverse after copy that array
so the code just need one liner like that
James
@aretecode
Jul 22 2017 11:39
That's just one of the many instances where that particular prototype is used
Kurt Milam
@kurtmilam
Jul 22 2017 11:39
Yes, but there's a difference in providing curried functions in your API and using them internally where they're unnecessary.
James
@aretecode
Jul 22 2017 11:40
Just was wondering if there was a written reason when writing with such an approach, not which way was better
Kurt Milam
@kurtmilam
Jul 22 2017 11:42
The desire to avoid internal cross dependencies has been mentioned in several recent GitHub issues, and I believe the primary reason is to increase modularity.
For example: ramda/ramda#2237
Vadim Nekrasov
@barbiturat
Jul 22 2017 16:38
How to work with functors via ramda’s “lens" methods?
For example, here is a “lensProp” signature:
Lens s a = Functor f => (a → f a) → s → f s
How to implement it in a real example?
And here is an “over's” signature:
Lens s a = Functor f => (a → f a) → s → f s
What does mean “s” argument?
Tomáš Konrády
@tommmyy
Jul 22 2017 17:33
Hello, are there any examples of WebApps written in pure functional style (using eg. combo of React/Ramda/Ramda-fantasy/Redux)? I am insterested in how to use principles from https://github.com/MostlyAdequate/mostly-adequate-guide in real life web app development.
Jonah
@jonahx
Jul 22 2017 18:35
is there a version of R.lensProp for selecting multiple properties rather than just one?
@tommmyy, you might like https://github.com/foxdonut/meiosis/wiki
Viktor Dzundza
@captainkovalsky
Jul 22 2017 20:27
hi guys
Jonah
@jonahx
Jul 22 2017 22:23
@JAForbes @davidchambers or anyone else who knows: I’m about to do a python project (i have little python experience) and am looking for recs for the best functional libraries. so far i’ve found PyMonad and fn.py and tools. any experience with these or other advice?
Tomáš Konrády
@tommmyy
Jul 22 2017 22:37
@jonahx it looks great :) it proposed its own architecture. It is your repo? I would like to use Redux as a state manament pattern. But I am intereseted how to integrate fantasy-land types into it. I mean into production code... real apps, not just for fun
Jonah
@jonahx
Jul 22 2017 22:39
@tommmyy it’s not mine but i'm using it. it’s by @foxdonut who you can find on the mithriljs find ususally. it would be a replacement for redux. you wouldn’t use redux with it. it basically is redux implemented in 6 lines, using streams.
Vadim Nekrasov
@barbiturat
Jul 22 2017 22:40
Is there any built in ramda ability to perform some action on the tree? For example, recursive search, or transforming all leaf values to upperCase (or perform other custom actions on leafs)?
Jonah
@jonahx
Jul 22 2017 22:42
@barbiturat i don’t believe so.
Tomáš Konrády
@tommmyy
Jul 22 2017 22:42
@jonahx do you work in a team? how did you convinced them use the pattern... I find it difficult even with Ramda :-(
James
@aretecode
Jul 22 2017 22:42
@barbiturat it depends how deep you want to traverse, but there is traverse and lense so you could say lenseProp your leaf nodes, or compose a matcher & an updater/setter, transform it that way
Jonah
@jonahx
Jul 22 2017 22:43
@tommmyy yeah that might be a hard sell. i had the luxury of making the decision myself because i’m the only dev on the project.
what might help is that you’re not selling them on a framework.
you’re just selling them on an approach to the architecture
James
@aretecode
Jul 22 2017 22:43
but the simplest way to do exactly that is by using https://github.com/substack/js-traverse (I've forked & tweaked it with pooling & v8 (de)opt checks https://github.com/fluents/chain-able/blob/v5/src/deps/traverse.js)
Vadim Nekrasov
@barbiturat
Jul 22 2017 22:44
@aretecode if we talk about unknown deepness of tree
James
@aretecode
Jul 22 2017 22:44
@barbiturat then traverse-js is made for that
Vadim Nekrasov
@barbiturat
Jul 22 2017 22:45
@aretecode Thank you for an info about the lib
Tomáš Konrády
@tommmyy
Jul 22 2017 22:46
@jonahx agreed. But in my team there are a lot of people that have background in Java.. it is fun sometimes... :D anyway, thank you for the tip
James
@aretecode
Jul 22 2017 22:46
no problem, it's a classic, I use it often, it simplifies a problem that can be easily over-complicated
James Forbes
@JAForbes
Jul 22 2017 22:46
I haven't used python for years and I didn't know any FP back then. I'm so surprised when people say they love python, I really do not miss it. Good luck :) @jonahx
James
@aretecode
Jul 22 2017 22:47
@barbiturat just be cautious because when I ran compiled v8 with d8 with irhydra2 locally to check for deopts, I got some big red dots, so I had to fork to make it better
Jonah
@jonahx
Jul 22 2017 22:47
@JAForbes haha, yes it seems like a solidly mediocre language to me. that said, it seems “fine.” and from what i can tell i will be able to write in a functional style easily enough with one of these libraries...
James Forbes
@JAForbes
Jul 22 2017 22:47
yeah definitely "fine" :D
"Python: It's fine"
James
@aretecode
Jul 22 2017 22:47
hahaha
James Forbes
@JAForbes
Jul 22 2017 22:48
I heard lambdas are better in python now than what they were
Jonah
@jonahx
Jul 22 2017 22:48
@JAForbes exactly. i basically feel the same about ruby now too though.
James
@aretecode
Jul 22 2017 22:48
at least ruby has on_missing_method
James Forbes
@JAForbes
Jul 22 2017 22:48
I was never a rubyist, I learnt a little here and there but again, I don't get why people gush about it :D
Vadim Nekrasov
@barbiturat
Jul 22 2017 22:49

Taking this opportunity (so many people online), I would like to repeat my question about misunderstanding the lenses in ramda

How to work with functors via ramda’s “lens" methods?
For example, here is a “lensProp” signature:
Lens s a = Functor f => (a → f a) → s → f s
How to implement it in a real example?

James Forbes
@JAForbes
Jul 22 2017 22:49
I had a ruby fan flat mate for years
James
@aretecode
Jul 22 2017 22:49
@barbiturat https://github.com/calmm-js/partial.lenses this is an example of someone using it
James Forbes
@JAForbes
Jul 22 2017 22:50
Like they are good languages etc, no problem if someone likes them, I am just at a loss why
James
@aretecode
Jul 22 2017 22:50
@barbiturat think about it like, you focus a lense on a specification/matcher, then you can view (getter) data matching it, or update (setter) data matching it
Vadim Nekrasov
@barbiturat
Jul 22 2017 22:51
But how to use FUNCTOR with lenses in ramda?
James Forbes
@JAForbes
Jul 22 2017 22:51
Oh no, what is on_missing_method @aretecode?
Does that let you call methods that don't exist and recover?
James
@aretecode
Jul 22 2017 22:51
@JAForbes it is like Proxy, but actually good and fast
https://github.com/ramda/ramda/blob/master/src/flip.js <- kind of weird that there is no flipN
James Forbes
@JAForbes
Jul 22 2017 22:51
ah ok
Jonah
@jonahx
Jul 22 2017 22:51
@JAForbes i think it’s all relative. when i first learned it, after java and php and others, i thought it was incredible. just the enumerable methods alone. but having learned haskell and J, it just seems like a kind of weird hybrid of ideas, like let’s just pour every bottle in the liquor cabinet into a punch bowl and get drunk.
James Forbes
@JAForbes
Jul 22 2017 22:51
I wish Proxy was never added personally :D
Vadim Nekrasov
@barbiturat
Jul 22 2017 22:52
@aretecode Im talking only about signature with FUNKTOR
Lens s a = Functor f => (a → f a) → s → f s
James
@aretecode
Jul 22 2017 22:52
java, php, python, ruby... at least they have standard libs
James Forbes
@JAForbes
Jul 22 2017 22:54
If JS had a standard lib, would we have lodash / ramda / sanctuary et al. I think standard libs are a bad idea, it means whatever was in fashion at the time the language was specced out is going to be the go to approach for all time, and then when you try to modernize it you have to keep backwards compatibility or risk a Python 3 situation.
Vadim Nekrasov
@barbiturat
Jul 22 2017 22:54

@aretecode lensProp has two signatures (from official doc):
http://ramdajs.com/docs/#lensProp

String → Lens s a
Lens s a = Functor f => (a → f a) → s → f s

Your example is the first one

But how to use second?

James
@aretecode
Jul 22 2017 22:55
@JAForbes maybe, maybe not, but it would make some things certainly easier
James Forbes
@JAForbes
Jul 22 2017 22:55
When its a library, you just throw it away and use a new one, if it suits your project. If anything I wish they'd leave the language alone and stop adding things.
Haha sorry I just had 3 coffees :)
@JAForbes I had 10 coffees worth of caffeine powder, we're even xD
James Forbes
@JAForbes
Jul 22 2017 22:56
caffeine powder! :D is that like coffee for astronauts?
James
@aretecode
Jul 22 2017 22:56
pretty much yup
99% caffeine powder, very dangerous :-P
James Forbes
@JAForbes
Jul 22 2017 22:57
Wow
Yeah you win this round
Vadim Nekrasov
@barbiturat
Jul 22 2017 22:57
@aretecode this example satisfies only to first signature of described above
James
@aretecode
Jul 22 2017 22:57
@barbiturat I'm just linking to the docs, I don't have more examples because I don't have a bunch of things that use it
@JAForbes I wish I could stop adding things to my libs instead and it would just be in the lang :-P
James Forbes
@JAForbes
Jul 22 2017 22:58
Just remembered writing incomprehensible comprehensions in python.
Vadim Nekrasov
@barbiturat
Jul 22 2017 22:58
@aretecode Sorry! ) Probably nobody has an experience of working with lenses on functors )
James
@aretecode
Jul 22 2017 22:59
@JAForbes which ramda function/method do you use the most?
@barbiturat if you play with it, add a pr with an example :-)
James Forbes
@JAForbes
Jul 22 2017 22:59
map? not sure
Vadim Nekrasov
@barbiturat
Jul 22 2017 22:59
@aretecode ok )
James Forbes
@JAForbes
Jul 22 2017 23:00
pipe is very common
I used to have a script that counted R.* in my projects and told me which functions I used most often
Doing that led me to discover I use almost the entire library often enough that cherry picking functions wasn't worth it.
Which was kind of a relief, now I just import the entire library
James
@aretecode
Jul 22 2017 23:01
I find when making utils, curry is easily the most used, and for client/apps it's usually map or construct or pipe
that's a lot of usage!
I forked the ones I used the most to adjust them how I'd like to use them https://github.com/fluents/chain-able/tree/v5/src/deps/fp
James Forbes
@JAForbes
Jul 22 2017 23:01
Yeah I have a rule where writing custom logic is a last resort
in applications, not in libraries
James
@aretecode
Jul 22 2017 23:02
for example, construct I prefer to have as both constructN + construct https://github.com/fluents/chain-able/blob/v5/src/deps/fp/construct.js#L27
Jonah
@jonahx
Jul 22 2017 23:03
@JAForbes do you ever use compose instead of pipe? i don’t understand why people do. left to right makes easier reading, plus… 3 extra chars!!
James Forbes
@JAForbes
Jul 22 2017 23:03
Yeah I use compose all the time, depends how I want to think about it
Jonah
@jonahx
Jul 22 2017 23:03
example?
James
@aretecode
Jul 22 2017 23:04
good rule for applications :+1:
James Forbes
@JAForbes
Jul 22 2017 23:04
Just searched compose in the file I'm currently working in
T(
    [['Read Permissions'
    ,'There are no read only permissions for this role'
    ]
    ,['Read & Write Permissions'
    ,'There are no write permissions for this role'
    ]
    ]
    ,pipe(
        map(
            ([a,b]) => xs => [
                m('h4.pa0.ma0.pb4', a)
                ,T(
                    xs
                    , Maybe.fold(
                        elements.alert('info', b)
                        ,compose(
                            xs => m('ul.list.details-permissions', xs )
                            ,map(
                                compose(
                                    x => m('li.pa2', x)
                                    ,Either.fold(
                                        x => m('span', {
                                            title: x +' is not deletable'
                                        }, x)
                                        ,elements.strikeItem('')
                                    )
                                )
                            )
                        )
                    )
                )
            ]
        )
        ,apply( Either.fold )
    )
)
James
@aretecode
Jul 22 2017 23:05
:s
James Forbes
@JAForbes
Jul 22 2017 23:05
Here I deliberately wanted to use compose because I'm generating hyperscript, so the structure here matches the output, but this is all within a pipe
James
@aretecode
Jul 22 2017 23:05
communicative code, sadness for the heart and soul
James Forbes
@JAForbes
Jul 22 2017 23:06
haha what @aretecode ?
Jonah
@jonahx
Jul 22 2017 23:07
@JAForbes are those fold methods from santuary?
James Forbes
@JAForbes
Jul 22 2017 23:08
That's just my own Maybe
Jonah
@jonahx
Jul 22 2017 23:09
@JAForbes what is that T doing there?
James Forbes
@JAForbes
Jul 22 2017 23:10
Just invoking the pipe immediately
James
@aretecode
Jul 22 2017 23:14
@JAForbes I mean it's short but it doesn't clearly communicate intention
James Forbes
@JAForbes
Jul 22 2017 23:15

So this is a view where there's 2 possibly empty lists, of permission objects that may or may not be editable. And I want to render differently based on a few states:

  • Is the list empty
  • Is the item editable
  • Is the item a read permission or a write permission

If its empty I show an alert:

elements.alert('info', b)

b is the help message from the array literal at the top.

If the item is editable I use a view called strikeItem that will render a strike through on hover and remove them item when you click on it:

elements.strikeItem('')

The '' is just a string of class names, in this case I just want the defaults. If its not editable, I just render a span with a title explaining why its different from the others.

 x => m('span', {
   title: x +' is not deletable'
}, x)

See how the li is above the span, and the ul is above the li, that's thanks to compose.

@aretecode You've spent seconds looking at it out of context, bit quick to make that call isn't it? :D
Jonah
@jonahx
Jul 22 2017 23:19
@JAForbes i dont understand how T is passing the arragy into the pipe
James Forbes
@JAForbes
Jul 22 2017 23:19
So that T is generating 2 very similar pipelines, that are executed as part of a larger pipeline that just isn't in that snippet.
James
@aretecode
Jul 22 2017 23:20
@JAForbes indeed, but in those seconds it either clearly communicates or does not, right? Just think how it would be if you didn't have such familiarity with the domain and library methods
James Forbes
@JAForbes
Jul 22 2017 23:20
The array comes in as ([a,b]) =>
Jonah
@jonahx
Jul 22 2017 23:20
@JAForbes i got that, but does T pass one argument to the next?
James Forbes
@JAForbes
Jul 22 2017 23:21
Yeah T passes that list into map which is generating a pipeline that takes x =>
@aretecode I firmly believe a small investment in learning domain and library methods pays off enormously, even in the short term
What I'm doing isn't adhoc, its not stuff I invented. I didn't make up T or fold or Either. So learning these things will be useful not just for this function but for all time.

@jonahx The nesting here was deliberate, it actually used to be a flat pipeline with no nesting, just taking advantage of Either.bimap to defer branching logic. But it didn't resemble the structure of the output so I went with this.

In other places I just go with flat

James
@aretecode
Jul 22 2017 23:23
@JAForbes yes, and I firmly believe crafting code that communicates the intentions with variable names describing the functionality is enourmously helpful. Right now it makes sense but you will always have cognitive overhead going back to understand it, even now you could see having to eplain it
James Forbes
@JAForbes
Jul 22 2017 23:25
Yeah we definitely have a different philosophy on this. When you name something, your carrying a mental model that I may not have, others on your team may not have, and you a year from now, may not have. Removing names altogether and thinking in terms of polymorphic data seems harder, but its completely honest in its complexity. And embracing that should be a prerequisite for editing code.
James
@aretecode
Jul 22 2017 23:27
Definitely different ends of a scale, while I wouldn't say either end is wrong, but totally different! DDD style vs minimal fp style :-P
James Forbes
@JAForbes
Jul 22 2017 23:27

And being terse wasn't my goal, it could be far terser. My goal was having the code match the structure of the output, and to separate the business logic from the presentation.

The processing has already been handled just above this. We've got a Maybe of a list of Eithers. And that's the part I am going to edit more often. So its nice to have that completely separated. When I edit this section I know I'm just dealing with presentation, so it makes sense to present the computation in the same structure as its output.

I'm using DDD directly above this, it depends what you are doing, right tool and all that.
James
@aretecode
Jul 22 2017 23:29
1:1 matching, has some benefits fosho, maybe when I'm back at laptop I'll write it with descriptions to compare
Jonah
@jonahx
Jul 22 2017 23:29
@JAForbes i think we have similar aesthetics, but i disagree with this claim: "When you name something, your carrying a mental model that I may not have…” If you’re on a team, you have a shared mental model, one way or another. You may as well make it explicit. Otoh, I agree that every name introduces a point of complexity, so I think there’s tension between the two goals. But I don’t believe you can just blanket take the approach of “no names”… that's dishonest in a different way
ah i see you just clarified that it depends on your level of abstraction
ok, i think we do agree. to be clear, i have no issue with code like yours in the right place.
ttyl
James Forbes
@JAForbes
Jul 22 2017 23:33

Here's a more ddd section. This is rendering a heading in an editing pane.

const heading =
    T( editing, pipe(
        editingToMaybe
        ,Maybe.map(
            pipe(
                Loadable.fold(
                    Either.Left('Loading '+label+' Data')
                    ,Either.Right
                )
                ,Either.map(
                    pipe(
                        Validatable.fromValidatable
                        ,Modifiable.fromModifiable
                    )
                )
                ,Either.map(
                    Saveable.fold(
                        K( 'Creating new ' + label )
                        , o =>
                            [ 'Editing'
                            , label+':'
                            , T(
                                $X.of(resourceName).name(o)
                                , Validatable.fold(
                                    o => o.value
                                    ,a => a
                                )
                            )
                            ]
                            .join(' ')
                    )
                )
                ,Either.fromEither
            )
        )
        ,Maybe.toNullable
    ))

We've got this structure Loadable Validatable Modifiable Saveable

Loadable can be Loaded a | Loading

Validatable, Modifiable and Saveable are binaries, so Validatable = Valid a | Invalid b as an example.

Here I'm traversing that structure and rendering an appropriate message for different states. If I am not interested in a state, I just skip it Validatable.fromValidatable for example just skips that layer.

We're also handling the case where we are editing nothing currently, editingToMaybe, and in that case we just skip this whole computation, and render null which the hyperscript library treats as "don't render anything"
But we push those nulls to the edge of the composition
James Forbes
@JAForbes
Jul 22 2017 23:38
Here I'm using names, because its highly relevant to the output. In the other section it isn't.
But what's cool is, there are 5 or 6 different data structures this editing panel supports, and this section of code has 0 interest in that. To get a name for a given type I use $X.of( resourceName ) which spits out a bunch of methods that let me treat these different data sets in a polymorphic manner. Same thing with label (which is defined out of scope).
@jonahx ttyl :D