These are chat archives for ramda/ramda

29th
Aug 2016
James Forbes
@JAForbes
Aug 29 2016 01:35

@dtipson but say you import two libraries, that both check for the existence of a method, one of them finds it isn't there so it overrides it with its custom logic, and the other library sees its defined so it doesn't override. In a large project it would seem relatively indeterministic which library gets to override that method and that could be a cause for confusion.

So I still think overriding prototypes has to be a userland thing.

Drew
@dtipson
Aug 29 2016 01:41
the problem is still the "checking if it exists" in that case right? If both libraries define a conflicting method on a proto and that causes problems because they have different signatures, that at least shows up during development, when both libraries are first included and conflict. That's at least more catchable than if a long stable, no-longer updated/supported site is accessed by a browser with the method defined natively because of a language update (that new behavior just gets overridden)
I guess if, in the future, Array.prototype.sequence is defined in the language with an unexpectedly weird type signature, then R.sequence would break, since it delegates to any .sequence method, so it wouldn't implement the Array behavior case it has currently
Jonah
@jonahx
Aug 29 2016 05:39
is there a ramda function like path but which allows string paths, ie, path(‘a.b’) rather than path([‘a’, ‘b’])? i know i could easily create my own with a decorator fn but thought it might be built in somewhere i’m not seeing….
Jonah
@jonahx
Aug 29 2016 05:46
separate question: i noticed ramda doesn’t provide a maybe function, which would decorate a normal fn such that it passes thru null or undefined values. is there a design reason for this omission or is it supported in some way i’ve missed?
Matt McKellar-Spence
@MattMS
Aug 29 2016 06:41
@jonahx I know that @davidchambers has thoughts on types, you could check out his Sanctuary library (https://github.com/sanctuary-js/sanctuary) for adding that sort of functionality to Ramda.
James Forbes
@JAForbes
Aug 29 2016 06:52

@dtipson it depends, I'm saying the user can explicitly show which library gets to be on the prototype, instead of it being a non deterministic thing. It might happen via checking, or it might just be the user determining which library wins.
If some browser implements some future thing, but the users code ignores it - its still ok to use the library they opted for years ago.

E.g. ramda and lodash both have methods. I could decide I want to dispatch to lodash's difference method instead of ramda in some instance. Later on, the browser implements difference, but it doesn't matter, I am still using the lodash difference I opted into years ago, because I never checked for browser support in the first place.

So in userland its safe. But if a library overrides the prototype, its probably going to hurt.

Churchill Lee
@FeliciousX
Aug 29 2016 08:16
@rickmed hv u checked out stream libraries? like RxJS , Bacon.js , xstream , Most.JS or etc?
streams allow u to model value over time and treat it like how u would treat an array
that's an oversimplification but using stream libraries would definitely help in that sense that u dont hv to worry about time
in a way..
take my point with a grain of salt as i am new to all these aswell :)
James Forbes
@JAForbes
Aug 29 2016 08:28
@rickmed @FeliciousX is right. Most stream libraries have operators for debouncing/throttling. e.g. https://github.com/paldepind/flyd/tree/master/module/aftersilence
Churchill Lee
@FeliciousX
Aug 29 2016 08:49
just a note http://jsbin.com/yumila/1/edit?js,console
I implemented the algorithm u guys talked about for Threes
it's a little buggy still
but now we can work from there
thank you @JAForbes @rjmk @buzzdecafe for the input
great learning experience
James Forbes
@JAForbes
Aug 29 2016 08:50
absolute pleasure @FeliciousX
Rick Medina
@rickmed
Aug 29 2016 13:12
@FeliciousX @JAForbes thanks. I'm familiar with many of those libraries. I just wonder how that kind of async stuff fits with a js style in terms of futures, eithers, maybes, etc. Put in another way, does haskell have a rxjs (or whatever) equivalent library? how would I do it in haskell If a want, let's say, to throttle a click, then do an ajax, but cancel the first ajax if another click comes through, do another ajax depending on that result, etc...
(setting a hypothetical example of haskell in the browser, but can be something similar in the server)
James Forbes
@JAForbes
Aug 29 2016 13:16
I am no haskell expert, but I think you're asking, is there a generic / monadic way to express throttling / debouncing?
Rick Medina
@rickmed
Aug 29 2016 13:18
yes, that would help a lot.
James Forbes
@JAForbes
Aug 29 2016 13:21

So, I don't think there is. I think Monads give you a set of laws for interacting with delays/debouncing etc, but debouncing and throttling are impure. So its up to the datatype to implement its own debouncing itself.

But its an interesting question/point! I am going to reflect on it

Rick Medina
@rickmed
Aug 29 2016 13:29
:thumbsup: !
Ryan Zeigler
@rzeigler
Aug 29 2016 14:58
Well think of it this way @JAForbes In a streaming context if every event is a time+data you can implement it as a scan->filter->map where you track the last emit in the accumulator and decide if emmitting. A filter to choose accumulators that actually have emits and a map to get out the data. Obviously the source is usually effectful but the throttle or denounce need not be.
That said I don't think that is how its implemented inside of rxjs and similar.
James Forbes
@JAForbes
Aug 29 2016 14:59
@rzeigler yeah but the implementation of scan has to exist first within the data structure, and each stream has to bring that themselves
Ryan Zeigler
@rzeigler
Aug 29 2016 15:01
Scan is a fairly useful/standard sequence combinator though. I don't think it's unreasonable to assume its existence.
James Forbes
@JAForbes
Aug 29 2016 15:01
E.g. flyd has combine, most has most-subject. they tend to have some proprietary underlying layer for efficiently creating these interfaces
Denis Stoyanov
@xgrommx
Aug 29 2016 15:01
:)
Ryan Zeigler
@rzeigler
Aug 29 2016 15:01
Then there's all that work they did in clojures they did to make it so all sequences needed to do was support reduce and they get everything else.
James Forbes
@JAForbes
Aug 29 2016 15:02
Yeah scan is probably going to be there. But I think @rickmed is asking, is there some kind of generic function for that underlying mechanism that enables scan/debounce/throttle. Kind of like transducers were a generic underlying structure for lazy computations
Denis Stoyanov
@xgrommx
Aug 29 2016 15:03
(fn => fn(10))(x => console.log(x)) that all what u should know about reactive in js :smile:
Ryan Zeigler
@rzeigler
Aug 29 2016 15:04
I became unreasonably angry the other day when rxjs5 broke my code.
James Forbes
@JAForbes
Aug 29 2016 15:05
what happened?
Ryan Zeigler
@rzeigler
Aug 29 2016 15:05
Not actually but their map passes a 2nd parameter for the index which made my point free stuff barf
James Forbes
@JAForbes
Aug 29 2016 15:05
ah! no!
the curse of "JS compatibility"
Ryan Zeigler
@rzeigler
Aug 29 2016 15:05
And it took me forever to figure out because I was just getting undefined from deep inside r.view
Because it was propping on a number
I guess I should have read the docs more closely. But I expect map to work a certain way.
James Forbes
@JAForbes
Aug 29 2016 15:07
yeah I've felt that pain with lodash in the past before /fp
Ryan Zeigler
@rzeigler
Aug 29 2016 15:07
And typescript didn't even save me because and r.curriedfunction2 can be used in either case.
James Forbes
@JAForbes
Aug 29 2016 15:07
Typescript tries, bless it :)
Ryan Zeigler
@rzeigler
Aug 29 2016 15:07
Which makes me wonder if there might be a benefit to a 'strict curry'
To save us from weird cases like this.
James Forbes
@JAForbes
Aug 29 2016 15:08

I tried to write a titlecase function today var f = ([head, ...tail]) => head.toUppercase() + tail

f('hello') //=> 'Hello'

Totally valid JS. But you get a type error in typescript.

Ryan Zeigler
@rzeigler
Aug 29 2016 15:09
Can you rest destructure a string?
I did not realize that.
James Forbes
@JAForbes
Aug 29 2016 15:09
Yeah, and you can destructure any iterator too! :D
Ryan Zeigler
@rzeigler
Aug 29 2016 15:10
Then again I don't think ts supports all of es6
James Forbes
@JAForbes
Aug 29 2016 15:11
@paldepind's UnionType uses destructuring to great affect. Its so nice destructuring a deeply nested complex structure that isn't even an array behind the scenes.
I'm pretty happy with the TS beta, super impressed actually
So its not all bad
just niggles
Ryan Zeigler
@rzeigler
Aug 29 2016 15:12
Grumble... No higher kinds. Grumble.
James Forbes
@JAForbes
Aug 29 2016 15:12
yeah tell me about it
there is movement on that though
Ryan Zeigler
@rzeigler
Aug 29 2016 15:13
Work has gone like all in on ts. And there was some entirely not functional code I was trying to type and I was just like. This would be easy with higher kinds.
James Forbes
@JAForbes
Aug 29 2016 15:13
I have my own ramda tsd, it just assumes unaries, it covers the 99% use case for me and catches way more errors
Ryan Zeigler
@rzeigler
Aug 29 2016 15:13
Not even just because I want my functor interface.
Rick Medina
@rickmed
Aug 29 2016 15:13
Yeah scan is probably going to be there. But I think @rickmed is asking, is there some kind of generic function for that underlying mechanism that enables scan/debounce/throttle. Kind of like transducers were a generic underlying structure for lazy computations
^^This
James Forbes
@JAForbes
Aug 29 2016 15:13
@rzeigler yeah if you want to write point free functor code, you kind of need to enable implict any, or its just awkward
but you can get pretty far with overloads, its surprising
Rick Medina
@rickmed
Aug 29 2016 15:14
There's a library somewhere that implemented somehow HKT with flow, but I'm not sure if it is valid and/or can be transported to typescript
James Forbes
@JAForbes
Aug 29 2016 15:15
I just keep adding things as I need them

@rickmed I think that example is missing what @rzeigler and I are lamenting as well.

If you pass a Maybe Maybe Number into a function, the very best TS will ever give you back is a Functor<T>

I think its the same in Flow
Rick Medina
@rickmed
Aug 29 2016 15:18
mmm got it!, yeah not very helpful...
James Forbes
@JAForbes
Aug 29 2016 15:20
but there are a few issues open on their github to change this though, it is on the roadmap
The other thing that is unrepresentable in TS is mapping over a record and transforming the values but retaining the structure
Rick Medina
@rickmed
Aug 29 2016 15:22
so if ts gives back functor and many things in fp is a functor, how is it useful?
James Forbes
@JAForbes
Aug 29 2016 15:22

e.g. R.map( String, { age: 10 }) // => {age: "10"}

You can't tell typescript that it returns the same structure. It just thinks its a dictionary now.

There are still plenty of cases where you don't need higher kinded types, and in those cases its really useful

e.g. you could write something like this

R.pipe(
  R.head
  ,R.multiply(10)
)

And if you define head as (list: <T>[]) : T | null then you'll get a type error because multiply expects a number not number | null

Ryan Zeigler
@rzeigler
Aug 29 2016 15:24
It can be frustrating if you want to define an interface for things that return keep kinds.
Let me give you a not fp example.
James Forbes
@JAForbes
Aug 29 2016 15:25
And it will give you really helpful type errors without any annotations. Particularly in the beta for 2.0
Ryan Zeigler
@rzeigler
Aug 29 2016 15:26
I want a web request factory that should return promised. You can't have one implantation that declares it returns specufically q promises and another that returns es6
Denis Stoyanov
@xgrommx
Aug 29 2016 15:26
@JAForbes then u should to use safe version of head like maybeHead with Maybe container
@JAForbes and use monad like maybeHead(list) >>= multiply(10)
James Forbes
@JAForbes
Aug 29 2016 15:27
@xgrommx yeah sure, but I'm just demonstrating that typescript is detecting a nullable within a point free composition : which is cool

So then you could fix it by going

R.pipe(
  R.head
  ,R.when(R.is(Number), R.multiply(10))
)

(Putting monads to the side for a second)

And the compiler will be happy now
because R.is will probably accept any and can handle the possible null from R.head
So you can write functional code in TS, it just falls apart when you have more than 1 level of functor
And even 1 level is awkward
Ryan Zeigler
@rzeigler
Aug 29 2016 15:29
I'm haven't tried I assume monad transformers are complete nonstarters.
They would have to rely on higher kinds.
James Forbes
@JAForbes
Aug 29 2016 15:35
blob
So here is a stream of some complex transform of some typed data from the server. It works. Its not elegant, but it works.
The stream is a Functor
Ryan Zeigler
@rzeigler
Aug 29 2016 15:36
Yeah. I'm of the mind I'm uninterested in a type system where I have to cast types like that.
James Forbes
@JAForbes
Aug 29 2016 15:37
Usually you don't have to, if it can infer the type based on the result from the previous function

But even though I had to cast the type of the pipe, all the other functions in the composition will now tell me if I cast it incorrectly.
And in this particular file there are Index's and Nested indexes, and they can contain lists and nested lists of various data. And it will tell me if picked the wrong function, or if my cast doesn't make sense.

So, yeah not elegant, but also not useless

Ryan Zeigler
@rzeigler
Aug 29 2016 15:53
i am fairly impressed that merge works as expected in ts though
the structural types stuff seems to work quite well
Aadi Deshpande
@cilquirm
Aug 29 2016 19:59
Hi here, is this a place where I can ask to ‘ramda-fy’ my code better?
For example, I have
 Immutable({
    type: "components/article/hero-image",
    version: 1
  }).set("data", (
    R.when(() => exists(obj.caption), (o) => o.set('caption', obj.caption))(
      R.when(() => exists(obj.credit), (o) => o.set('credit', obj.credit))(
        Immutable({
          src: obj.url.replace('https://mysite.com', 'http://mysite.com'),
          width: obj.width,
          height: obj.height
        })
      )
    )
  ))
where exists is defined as
const exists = R.complement(R.either(R.isNil, R.isEmpty));
LeonineKing1199
@LeonineKing1199
Aug 29 2016 20:18

What @xgrommx was pointing out is that map has the nice signature, Functor f => (a -> b) -> f a -> f b. It works for any functor, including an array. Of course mostly the implementation > is up to you. But if you have a FantasyLand-compatible Functor, Ramda's map will work with it. And that's all it does.
Trying to add additional behavior loses too much of the simplicity that Ramda strives for.

I'm looking at the implementation details and I think the confusion is making map like fmap in Haskell where it makes more sense and is also supported by a stronger type system.

Haskell's native map is (a -> b) -> [a] - > [b]
While fmap is (a -> b) -> f a -> f b
Denis Stoyanov
@xgrommx
Aug 29 2016 20:18
@LeonineKing1199 fmap for array is map
LeonineKing1199
@LeonineKing1199
Aug 29 2016 20:19
I mean, that's fine.
Ryan Zeigler
@rzeigler
Aug 29 2016 20:19
In fact the typeclass literally has fmap = map in it.
LeonineKing1199
@LeonineKing1199
Aug 29 2016 20:19
But if map was supposed to be fmap, it does a terrible job of calling map and for some reason does an imperative loop manually
when Array.prototype.map is available.
Denis Stoyanov
@xgrommx
Aug 29 2016 20:20
@LeonineKing1199 here real fp map =) https://esnextb.in/?gist=d7c26ad46f4878d68c814c0c66e89191
LeonineKing1199
@LeonineKing1199
Aug 29 2016 20:20
And what about maping over an object?
It's bummer JS doesn't have operator overloading.
Regardless, map is almost a misnomer, given its seemingly intended meaning.
To be consistent and more formal, shouldn't map ultimately just be this?
const fmap = (f, cb) => f.map(cb);

const a = [0, 1, 2];
const cb = x => x * x;

fmap(a, cb) // => [0, 1, 4]
Ryan Zeigler
@rzeigler
Aug 29 2016 20:24
It's all pedantry though. Like I got over that fact chain isn't called flat map or bind as well.
You just need to know the ramda map is a functor lift.
LeonineKing1199
@LeonineKing1199
Aug 29 2016 20:25
I mean, I wish it was. But the implementation details and object support seem to conflict with that.
I'm surprised that arrays aren't treated as map-ables and instead are manually looped.
Ryan Zeigler
@rzeigler
Aug 29 2016 20:26
Why. Objects are containers. I haven't proved it but the object support meets the functor laws.
LeonineKing1199
@LeonineKing1199
Aug 29 2016 20:26
And I'm surprised that objects are supported.
Ryan Zeigler
@rzeigler
Aug 29 2016 20:26
Which is all that really matters.
LeonineKing1199
@LeonineKing1199
Aug 29 2016 20:27
I mean, it was just my thought that because Ramda is already doing the for-loop, it might as well loop over N arrays
Then you could map over a variable number of lists and get one super awesome transform out of it.
Ryan Zeigler
@rzeigler
Aug 29 2016 20:29
one can use map(…(map(f))…) for that
or, if you have some weird polymorphic arrays structure you do mix in cond's
LeonineKing1199
@LeonineKing1199
Aug 29 2016 20:30
Recursive map calls like that is I think O(m * n) complexity.
Ryan Zeigler
@rzeigler
Aug 29 2016 20:30
so is looping over each element in a nested array
by for loops
i think you are missing the log n though
LeonineKing1199
@LeonineKing1199
Aug 29 2016 20:31
Okay, if I said 'zip iterator' would that mean anything?
Ryan Zeigler
@rzeigler
Aug 29 2016 20:31
because it fans out like tree
yes
LeonineKing1199
@LeonineKing1199
Aug 29 2016 20:31
Aweseome!
Ryan Zeigler
@rzeigler
Aug 29 2016 20:31
but you are looking at using arrays like atree
rather than a sequence
LeonineKing1199
@LeonineKing1199
Aug 29 2016 20:31
A tree?
How so?
But anyway, yeah, if we "zip iterated" through a collection of lists, that's just O(n)
Ryan Zeigler
@rzeigler
Aug 29 2016 20:32
maybe im not understanding your dillema
LeonineKing1199
@LeonineKing1199
Aug 29 2016 20:32
Basically, I kind of want this
const a = [0, 1, 2];
const b = [3, 4, 5];
map(add, a, b); // => [3, 5, 7]
Ryan Zeigler
@rzeigler
Aug 29 2016 20:33
so you want map to do zipWith
when they are different
LeonineKing1199
@LeonineKing1199
Aug 29 2016 20:34
Oh that's so funny, there's zipWith
But I don't want to be limited to just two arrays though.
My example used to but it should work for N arrays of size M
If you wanna apply that change to zipWith and not map, that's fine with me.
Still a useful feature.
In the JS ecosystem, map is a pretty list-centric function so that's why I suggested changing map first.
Should've been map as a List function, fmap as the functor generalization and then Idk about zipWith
Rafe
@rjmk
Aug 29 2016 20:42
@LeonineKing1199 The reason it doesn't delegate to Array.prototype.map is probably because that function is not a lawful functor map (supplying functions with the index and array is not lawful)
LeonineKing1199
@LeonineKing1199
Aug 29 2016 20:44
JS wasn't built from the ground-up like other FP languages though. It's a multi-paradigm language with dynamic typing and weak types.
It's got awesome FP support but you'll never implement "pure" FP in a language that at its core is fundamentally impure
Rafe
@rjmk
Aug 29 2016 20:46
@LeonineKing1199 Certainly people are not suggesting JS is the best language for doing FP, but many people find doing FP (including ideas found in strongly typed languages) in JS useful
LeonineKing1199
@LeonineKing1199
Aug 29 2016 20:53
So, now that the language is a bit more clear, variadic zipWith, yay or nay?
JS has amazing support for variadics.
Part of my philosophy has always been to embrace the language and use it for all that it is and has to offer. I think the arguments object can allow for a very powerful application of variadic programming here
Rafe
@rjmk
Aug 29 2016 20:55
Variadic functions are definitely my least favourite thing about Ramda, so :-1: from me (I long for a module called strict-curry that would return a series of one arg functions). Arguably one that took an array would be OK
LeonineKing1199
@LeonineKing1199
Aug 29 2016 20:55
Really? What is it about them that you don't like?
Brad Compton (he/him)
@Bradcomp
Aug 29 2016 20:56
I would appreciate a variadic zipWith (or one that took an array of arrays), though it would make currying difficult.
Rafe
@rjmk
Aug 29 2016 20:56
I do totally get your point about working with the language you have. Perhaps I am fighting JS too much, but I find I have productive workflows with Ramda/Sanctuary/etc that are frustrated by variadics
LeonineKing1199
@LeonineKing1199
Aug 29 2016 20:56
Keep in mind, unlike super awesome statically-typed languages, JS does not have zero-cost abstractions.
Brad Compton (he/him)
@Bradcomp
Aug 29 2016 20:56
Maybe a zipNWith :: Number -> fn -> ...arrs
LeonineKing1199
@LeonineKing1199
Aug 29 2016 20:56
Returning arbitrarily curry-able functions is not free and there's no compiler to do awesome things like inlining function calls.
I've seen some Rust and it seems like Rust really favors FP stuff
I think instead of bind or >>=, they have and_then
Rafe
@rjmk
Aug 29 2016 20:58
They don't play nicely with higher order functions. Mostly this comes up when I've made a mistake, it's true. I'll try and write up an example
@Bradcomp I think zipNWith is liftN for zipArrays
Though it's true the implementation could be more efficient than liftN
LeonineKing1199
@LeonineKing1199
Aug 29 2016 21:00
Ooh, there's liftN
Rafe
@rjmk
Aug 29 2016 21:00
Yeah, it's true it's not free. There are many circumstances where I want abstraction and to reason in a certain way in my app without it necessarily being a hot path. Then the performance tradeoff is worth it. Other times, perhaps not
LeonineKing1199
@LeonineKing1199
Aug 29 2016 21:01
But what if I want abstraction and performance?
Rafe
@rjmk
Aug 29 2016 21:02
Sadly liftN wouldn't work for your needs on a normal array as we've defaulted to a different applicative instance for arrays
In some cases that's easy to come by and in some not? I assume you mean in JS code because otherwise looking at another language if you stringent performance concerns might be necessary
LeonineKing1199
@LeonineKing1199
Aug 29 2016 21:03
So, speaking of implementing FP in other languages, you guys ever see the FTL?
Eh, JS is largely fast enough for us.
Plus, there's a threadpool module that we could theoretically use
This message was deleted
Denys Dovhan
@denysdovhan
Aug 29 2016 21:20
hi
can anyone suggest the article about how to read signatures of functions?
like [(*… → Boolean)] → (*… → Boolean)
Brad Compton (he/him)
@Bradcomp
Aug 29 2016 21:21
@denysdovhan Check out the article here on the wiki: https://github.com/ramda/ramda/wiki/Type-Signatures
Denys Dovhan
@denysdovhan
Aug 29 2016 21:21
I understand what it means, but I'm not always sure in that
@Bradcomp oh, thanks
Denis Stoyanov
@xgrommx
Aug 29 2016 21:34
@denysdovhan this is notation of Hindley-Milner. ... is rest of arguments