These are chat archives for ramda/ramda

18th
Jun 2015
Scott Christopher
@scott-christopher
Jun 18 2015 01:20
Regarding the recent, somewhat passionate discussions about dispatching in #1173, I decided to have a play around with moving the conditional dispatching outside of the individual functions and into external objects.
With the idea being that the existing dispatching logic could still be kept within Ramda’s reach, either already being applied to the distributed R object, or left up to the user to apply as needed.
It then allows others to provide their own dispatch conditions for things such as jQuery objects, etc.
Thoughts?
Hardy Jones
@joneshf
Jun 18 2015 02:19
Reading now.
I've not been following along.
Scott Christopher
@scott-christopher
Jun 18 2015 02:24
On a side note @joneshf, does declaring something as a semigroupoid actually provide anything beyond what a semigroup instance for the individual morphisms would offer? (if that makes sense)
Hardy Jones
@joneshf
Jun 18 2015 02:28
In js it's tough to see what the point is since there's no concept of polymorphic types.
but in general there is a purpose.
Functions, for example, have both Semigroup and Semigroupoid implementations.
and they behave differently
Scott Christopher
@scott-christopher
Jun 18 2015 02:29
Ah, ok. This may be where my understanding is off. :)
Hardy Jones
@joneshf
Jun 18 2015 02:30
λ: (++ "wat") <> (++ "yep") $ "hi"
"hiwathiyep"
λ: (++ "wat") . (++ "yep") $ "hi"
"hiyepwat"
top is Semigroup (Monoid actually), bottom is Semigroupoid (well, not really but same implementation)
Scott Christopher
@scott-christopher
Jun 18 2015 02:32
I had just assumed the bottom was both. Thanks!
Hardy Jones
@joneshf
Jun 18 2015 02:33
Np. It'd take more careful defining to denote the difference, since we can't just defer to the types.
Scott Christopher
@scott-christopher
Jun 18 2015 02:33
So does the monoid instance require it’s argument and result to be monoid instances too?
Hardy Jones
@joneshf
Jun 18 2015 02:34
just the result
Scott Christopher
@scott-christopher
Jun 18 2015 02:34
sure, that makes sense
Hardy Jones
@joneshf
Jun 18 2015 02:34
λ: show <> show $ 3
"33"
Scott Christopher
@scott-christopher
Jun 18 2015 02:36
So if I understand correctly, Semigroupoids are just Categories without an identity morphism?
Hardy Jones
@joneshf
Jun 18 2015 02:45
yep
David Chambers
@davidchambers
Jun 18 2015 02:53
Can anyone explain what makes Extend useful? map and chain provide the unwrapped value (e.g. 42) whereas extend provides the wrapped value (e.g. Just(42)). I’m struggling to see what one can do with a wrapped value besides using map and chain! :)
Hardy Jones
@joneshf
Jun 18 2015 03:02
you can do all sorts of things!
anything where you need to make a decision based on what the rest of a data structure looks like is a use case for extend.
or where you are in the data structure
you can derive zippers from there (I think, aybe you need a full comonad), you can do stuff like cellular automata, you can implement menus in a ui, you can fold a data structure, you can fake oo design patterns.
lots of stuff.
Hardy Jones
@joneshf
Jun 18 2015 03:10

See for instance

:point_up: May 22, 2015 12:00 AM

From which you can derive isRight and either as a catamorphism as @gilligan did above that.

David Chambers
@davidchambers
Jun 18 2015 03:50

Thanks, @joneshf.

Here’s @gilligan’s either implementation:

// either :: Either a b -> (a -> c) -> (b -> c) -> c
var either = function(x, leftF, rightF) {
    return isRight(x) ? x.chain(rightF) : leftF(x.value);
};
Asaf
@asaf-romano
Jun 18 2015 03:54
@scott-christopher note that one minor issue with that path is that you won;t be able to do something like |import { map } from "ramda"| if you want to dispatch. You'd either have to move the wraped-up ramda into its own module and import from that, or import R first, then override it however you like (assuming linters allow that), and the use let destructing (let { map } = R)
David Chambers
@davidchambers
Jun 18 2015 03:56

I’m looking for a small example. Here’s a small example for map which I find compelling:

> Just(5).map(square)
25

Here’s a small chain example:

> Just('[1,2,3]').chain(S.parseJson)
Just([1, 2, 3])

Is there something similar for extend. Right now I have:

> Just(42).extend(function(m) { return m.value + 1; })
Just(43)

This accesses the “private” value property, which isn’t ideal. More importantly, though, it’s not showing off the characteristics which make extend more useful in certain contexts than map or chain.

Hardy Jones
@joneshf
Jun 18 2015 04:27
I don't think Maybe provides very interesting Extract examples by itself simply because it's such a simple type. But move into slightly more complex types and it shows you some pretty interesting things. Like summing all the children in a tree. or stuff like that.
λ: extended sum [1..10]
[55,54,52,49,45,40,34,27,19,10]
λ: let tree = Node 4 [Node 2 [Node 1 [], Node 3 []], Node 7 [Node 6 [], Node 9 []]]
λ: putStr $ drawTree $ show <$> tree
4
|
+- 2
|  |
|  +- 1
|  |
|  `- 3
|
`- 7
   |
   +- 6
   |
   `- 9
λ: putStr $ drawTree $ show <$> extended sum tree
32
|
+- 6
|  |
|  +- 1
|  |
|  `- 3
|
`- 22
   |
   +- 6
   |
   `- 9
Sorry, I know it's haskell, but I don't know of a tree implementation in js
and way too lazy to write one right now.
Also, as an aside, can we take a moment and reflect on how bad this Data.Tree api is. I have explicitly map showover the tree, then draw it...
Hardy Jones
@joneshf
Jun 18 2015 04:37
More ideas where extend is useful is in streams
also frp in general.
Asaf
@asaf-romano
Jun 18 2015 04:41
Does anyone have exp. with using ramda (somehow) to map over node.js streams?
something like what https://github.com/dominictarr/event-stream provides
David Chambers
@davidchambers
Jun 18 2015 04:45
Thanks, @joneshf! The extended sum [1..10] is compelling (and short). Also, I’m reading http://www.slideshare.net/davidoverton/comonad (which I imagine you’ve read). Thinking of a comonad as focus + context is helpful.
Hardy Jones
@joneshf
Jun 18 2015 04:49
I've not seen that. But even mentions Kleisli and CoKleisli :)
I've always liked the formulation of the laws with Kleisli vs bind, and feel like we should've done that for everything once we realized what it was.
but oh well, i guess we're stuck with bind
David Chambers
@davidchambers
Jun 18 2015 04:52
Does this look right?
// Array#extend :: [a] ~> ([a] -> a) -> [a]
Array.prototype.extend = function(f) {
  var result = [];
  for (var idx = 0; idx < this.length; idx += 1) {
    result.push(f(this.slice(idx)));
  }
  return result;
};
> R.range(1, 11).extend(R.sum)
[55, 54, 52, 49, 45, 40, 34, 27, 19, 10]
Hardy Jones
@joneshf
Jun 18 2015 05:40
seems like it
> var tails = function(xs) { return R.tail(xs.extend(R.identity)); }
undefined
> tails(R.range(1,10))
[ [ 2, 3, 4, 5, 6, 7, 8, 9 ],
  [ 3, 4, 5, 6, 7, 8, 9 ],
  [ 4, 5, 6, 7, 8, 9 ],
  [ 5, 6, 7, 8, 9 ],
  [ 6, 7, 8, 9 ],
  [ 7, 8, 9 ],
  [ 8, 9 ],
  [ 9 ] ]
David Chambers
@davidchambers
Jun 18 2015 06:43
That’s pretty cool. As you say, extend just isn’t as useful for Maybe or Either.
Asaf
@asaf-romano
Jun 18 2015 06:56
This message was deleted
hemanth.hm
@hemanth
Jun 18 2015 06:57
@joneshf Create a pascal triangle ;)
Asaf
@asaf-romano
Jun 18 2015 06:58
This message was deleted
This message was deleted
This message was deleted
ugh, wasn't there dropLast or somrthing like that?
David Chambers
@davidchambers
Jun 18 2015 07:08
@asaf-romano: R.init?
Asaf
@asaf-romano
Jun 18 2015 07:09
@davidchambers i meant last-n-chars
well, elements.
but the thing is that I have to switch to drop, it seems, and that doesn't support negative offset the way substringTo did
David Chambers
@davidchambers
Jun 18 2015 07:11
R.slice accepts negative offsets:
> R.slice(-3, Infinity, 'foobar')
'bar'
Asaf
@asaf-romano
Jun 18 2015 07:11
ew.
David Chambers
@davidchambers
Jun 18 2015 07:11
Were you doing something like R.substringFrom(-3)?
yep
David Chambers
@davidchambers
Jun 18 2015 07:12
That example could be written R.slice(0, -2, 'string'), which seems fine to me.
Asaf
@asaf-romano
Jun 18 2015 07:14
This is very subjective, bu I find R.drop/take etc very declarative, and R.slice the mechanical thing to run to when something is missing
maybe a general purpose "right-side" version of take and drop could help.
David Chambers
@davidchambers
Jun 18 2015 07:14
Ramda could potentially use -0 to indicate the position after the last index (as Sanctuary does). Then one could write R.slice(-3, -0) to make a “lastThree” function.
I agree that take and drop are declarative. Taking a negative number of elements isn’t intuitive, though. :)
Asaf
@asaf-romano
Jun 18 2015 07:16
I'm not saying it's, but that's how the substring api worked
not suggesting to mimic that in drop
but maybe init could be replaced with something that takes the number of elements to remove
(I guess the current signature reflects something common in fp languages though)
David Chambers
@davidchambers
Jun 18 2015 07:20
It looks like we’re missing two functions:
             [ 1 , 2 , 3 , 4 , 5 , 6 , 7 ]

       head    1
       tail      [ 2 , 3 , 4 , 5 , 6 , 7 ]
       last                            7
       init  [ 1 , 2 , 3 , 4 , 5 , 6 ]
    take(2)  [ 1 , 2 ]
    drop(2)          [ 3 , 4 , 5 , 6 , 7 ]
Asaf
@asaf-romano
Jun 18 2015 07:22
yeah (well, imo)
btw, I guess the plan is to also remove concat and make appends work on strings?
David Chambers
@davidchambers
Jun 18 2015 07:23
We could add:
takeLast(2)                      [ 6 , 7 ]
dropLast(2)  [ 1 , 2 , 3 , 4 , 5 ]
Asaf
@asaf-romano
Jun 18 2015 07:24
yes, for whatever reason I assumed dropLast was there, but undefined is not a function.
David Chambers
@davidchambers
Jun 18 2015 07:25
I see no reason to remove R.concat: R.concat([1, 2, 3], [4, 5, 6]) is something I do quite often.
Asaf
@asaf-romano
Jun 18 2015 07:25
regarding append etc, on a personal note, I'm finding 0.15 very confusing. I'm working on pipelines involving array of strings and such, and I have to go back to the docs very often
David Chambers
@davidchambers
Jun 18 2015 07:26
Because you’re not clear on which functions also work on strings?
Asaf
@asaf-romano
Jun 18 2015 07:26
I think it was a little early to deprecate the string-specific methods. That, imho, should have been done once the transition is complete.
yeah
e.g. init vs. tail
that's crazy :(
(tail returns an array)
and finding append more declarative than flip(concat), I tried to use that too.
David Chambers
@davidchambers
Jun 18 2015 07:29
I would like R.tail and R.init to work on strings, too. But the changes to R.take and R.drop set in motion a chain of events which has made us question the direction Ramda should take with its dispatching.
Asaf
@asaf-romano
Jun 18 2015 07:29
(R.init does work on strings now)
David Chambers
@davidchambers
Jun 18 2015 07:29
Have you considered R.concat(R.__, 'suffix')?
Asaf
@asaf-romano
Jun 18 2015 07:29
yeah, I read the thread.
that's quite the same, isn't it? flip basically sets a placeholder for the first element.
David Chambers
@davidchambers
Jun 18 2015 07:30
Oh, I wasn’t aware of the R.tail/R.init inconsistency. Thank you for bringing that to my attention!
Asaf
@asaf-romano
Jun 18 2015 07:31
can file it if you wish.
David Chambers
@davidchambers
Jun 18 2015 07:31
Please do.
Asaf
@asaf-romano
Jun 18 2015 07:31
sec.
David Chambers
@davidchambers
Jun 18 2015 07:32
The R.concat example could be done via R.flip, yes. I am rather partial to the placeholder myself, particularly when aliases as _: R.concat(_, 'suffix').
Asaf
@asaf-romano
Jun 18 2015 07:33
#1199
David Chambers
@davidchambers
Jun 18 2015 07:34
Thank you.
Asaf
@asaf-romano
Jun 18 2015 07:34
I guess there's no point filing dropLast/takeLast for now; I spammed with enough RFEs already :)
David Chambers
@davidchambers
Jun 18 2015 07:38
ramda/ramda#1200
RFE?
Asaf
@asaf-romano
Jun 18 2015 07:41
request for enhancement
David Chambers
@davidchambers
Jun 18 2015 07:41
Gotcha.
Asaf
@asaf-romano
Jun 18 2015 07:41
the bugzilla (well maybe just Mozilla's) term for proposal.
David Chambers
@davidchambers
Jun 18 2015 07:41
There’s no daily limit on the number of enhancement requests. Keep them coming. :)
Asaf
@asaf-romano
Jun 18 2015 07:42
when the number of issues open is double-digit, I always feel bad opening an issue about anything less than a fire.
David Chambers
@davidchambers
Jun 18 2015 07:44
I should sleep now. Night, folks!
Raine Virta
@raine
Jun 18 2015 07:47
good night, david
Stefano Vozza
@svozza
Jun 18 2015 10:31

Does anyone have exp. with using ramda (somehow) to map over node.js streams?

@asaf-romano Do you mean something like Highland.js? It's the main way we use Ramda in work.

Scott Sauyet
@CrossEye
Jun 18 2015 11:52
@svozza: how are you integrating Ramda and Highland?
Asaf
@asaf-romano
Jun 18 2015 12:20
@svozza I don't have any exp. with highland.js, but it seems relevant. Is there any online documentation about ramda-highland integration?
hehe, didn't see the next message
Raine Virta
@raine
Jun 18 2015 12:23
i'm also curious about where highland fits
Stefano Vozza
@svozza
Jun 18 2015 12:33

Well typically I don't use dispatch so I just do things like this:

var s = someNodeStream // (say it emits 1, 2, 3, 4)
hl(s).map(R.mulitply(4)).reject(R.lt(10)).toArray(console.log);
// => [12, 16]

If you don't like the chaining syntax you can use seq which is analagous to pipe.

var xs = hl.seq(hl.map(R.mulitply(4)), hl.reject(R.lt(10))) (hl(s))
xs.toArray(console.log);
// => [12, 16]

You have to call something like toArray or each at the end to cause a thunk and get the values from the stream. Highland is lazy and won't start reading until you've done that thunk.

But if you know your functions will dispatch in Ramda then something like this will work:

R.map(R.multiply(4), hl(s)).toArray(console.log);
//=> 4, 8, 12, 16
Raine Virta
@raine
Jun 18 2015 12:35
cool
Stefano Vozza
@svozza
Jun 18 2015 12:37
Pretty much all Highland functions have their methods available on the top level object (hl in my example). The stream to be operated on is the final argument and the functions are automatically curried.
Raine Virta
@raine
Jun 18 2015 12:39
have to say dispatching is a pretty unintuitive library feature but OTOH very useful
Stefano Vozza
@svozza
Jun 18 2015 12:42
yeah, like the dispatch to transducers is great, because i can just throw ES6 maps into reduce and they just work
Scott Sauyet
@CrossEye
Jun 18 2015 13:42
Thanks @svozza!
Stefano Vozza
@svozza
Jun 18 2015 15:41
it's nice not to feel woefully out of my depth here for once! :smile:
John-David Dalton
@jdalton
Jun 18 2015 15:49
@svozza dispatching is discussed more here #1173
Stefano Vozza
@svozza
Jun 18 2015 15:50
Yeah, we had a big thread on it when we started our explorations on how we could integrate Highland with Ramda too. Tricky problem!
Chet Harrison
@ChetHarrison
Jun 18 2015 15:55
@svozza I have been playing with RxJs
Jethro Larson
@jethrolarson
Jun 18 2015 18:07
seeking more ramda transducer examples
Raine Virta
@raine
Jun 18 2015 18:42
put it on cookbook if you come up with one ;)
Jethro Larson
@jethrolarson
Jun 18 2015 18:45
Okay. Maybe I'll even test it
David Chambers
@davidchambers
Jun 18 2015 20:02
Can anyone provide some examples of using Future or IO from ramda-fantasy? The documentation is rather sparse.
Raine Virta
@raine
Jun 18 2015 20:04
did tests give any hints?
Chet Harrison
@ChetHarrison
Jun 18 2015 20:04
check out https://vimeo.com/106008027 @davidchambers
David Chambers
@davidchambers
Jun 18 2015 20:05
The tests provide hints, certainly. Thanks for the link, @ChetHarrison!
Chet Harrison
@ChetHarrison
Jun 18 2015 20:05
:+1:
I think he did one on IO too
asaf-romano I cannot stress enough how much evolve shines in data-anonymization code.
David Chambers
@davidchambers
Jun 18 2015 20:36
That’s an incredibly instructive video!
Chet Harrison
@ChetHarrison
Jun 18 2015 20:36
:smile:
I think he did 4
David Chambers
@davidchambers
Jun 18 2015 21:39
Does Ramda provide an equivalent of the traverse function in that video?
Apparently it does! ramda/ramda#526
Chet Harrison
@ChetHarrison
Jun 18 2015 21:42
It's been a while since I watch the video but I know Lonsdorf uses Ramda
David Chambers
@davidchambers
Jun 18 2015 21:44
He was involved in the discussion surrounding the additions of R.commute and R.commuteMap.
Hardy Jones
@joneshf
Jun 18 2015 22:39
:+1:
Jethro Larson
@jethrolarson
Jun 18 2015 22:52
Is that good for the cookbook or where should it go?
David Chambers
@davidchambers
Jun 18 2015 23:35
Nice example!
Michael Hurley
@buzzdecafe
Jun 18 2015 23:38
if it's good enough for @joneshf and @davidchambers it's certainly good enough for me. cookbook sounds good too
Jethro Larson
@jethrolarson
Jun 18 2015 23:44
Okay, I may shorten it some for the cookbook
So if you see //:: Future a, b do you think Future(a, b) or Future(a), b?
Michael Hurley
@buzzdecafe
Jun 18 2015 23:50
the parens make it unambiguous
David Chambers
@davidchambers
Jun 18 2015 23:51
I would write Future a b.
Jethro Larson
@jethrolarson
Jun 18 2015 23:53
It looks like folktale does @Future[a, b]
Which kind of makes sense? like future is a monad and list is a monad so you could use brackets to say, this is the stuff in the monad
Hardy Jones
@joneshf
Jun 18 2015 23:59
Well, not entirely.