These are chat archives for ramda/ramda

11th
Sep 2017
Jonah
@jonahx
Sep 11 2017 00:33
@buzzdecafe your last example of ap is where i was getting confused by the ramda docs, which say: "ap applies a list of functions to a list of values.” and then noting that it operated on a different type class than haskell’s, i wondered if it was not a “true” ap, but maybe something just worked on lists...
Michael Hurley
@buzzdecafe
Sep 11 2017 00:39
yeah that could be improved. please send a PR if you have time/inclination
Jonah
@jonahx
Sep 11 2017 00:49
@buzzdecafe ah i see, ty. i will make note to do a PR, may not be for a bit as I’m trying to make a deadline atm.
Syaiful Bahri
@syaiful6
Sep 11 2017 01:55
the simple mirrorPivot i think is const mirrorPivot = ap(concat, o(tail, reverse))
Jonah
@jonahx
Sep 11 2017 02:15
@syaiful6 :thumbsup:
Jonah
@jonahx
Sep 11 2017 04:34
So in general, when the Applys are functions, ap works like: function(x) { return applyF(x)(applyX(x)); }. Is this the only possible implementation of ap for functions that follows the Apply composition law?
Akshay Iyer
@AkshayIyer12
Sep 11 2017 05:20
Hi
I was going through Mostly Guide to FP by Dr.Boolean
And he has used functions from ramda in his examples
I was trying to make a functor
'let Container = function (x) {
this.value = x
}
Container.of = function (x) {
return new Container(x)
}
// console.log(Container.of(3))
// console.log(Container.of('hotdog'))
// console.log(Container.of(Container.of({
// name: 'Yoda'
// })))
Container.prototype.map = function (f) {
return Container.of(f(this.
value))
}
// console.log(Container.of(5).map(function (two) {
// return two + 2
// }))
// console.log(Container.of('Flamethrower').map(function (s) {
// return s.toUpperCase()
// }))
console.log(Container.of('bombs').map(.concat(' away')).map(.prop('length')))'
I'm not able to understand the last line here
So Container.of('bombs') returns Container { __.value : bombs }
Oops! console.log(Container.of('bombs').map(.concat(' away')).map(.prop('length')))
_ is not coming in gitter I suppose
So How is map working with concat
Akshay Iyer
@AkshayIyer12
Sep 11 2017 05:26
When I console log till concat it displays Container { __value: ' awaybombs' }
Can anybody help why concat is appending in front of bombs?
Jonah
@jonahx
Sep 11 2017 05:55
@AkshayIyer12, can you edit your code an enclose it in triple backticks so it’s formatted correctly?
@AkshayIyer12, To answer your question, if you map(R.concat(R.__, ' away')) it should work, as concat adds the 2nd arg to the first
Jonah
@jonahx
Sep 11 2017 06:00
similarly, you could map(x => x + ' away')
Akshay Iyer
@AkshayIyer12
Sep 11 2017 06:02
@jonahx Thank you so much
Jonah
@jonahx
Sep 11 2017 06:02
np
Jonah
@jonahx
Sep 11 2017 06:08

continuing my previous question, trying to understand ap more deeply, consider the “list of functions to list of values” examples from the docs:

R.ap([R.multiply(2), R.add(3)], [1,2,3]); //=> [2, 4, 6, 4, 5, 6]
R.ap([R.concat('tasty '), R.toUpper], ['pizza', 'salad']); //=> ["tasty pizza", "tasty salad", "PIZZA", "SALAD"]

I understand what is happening, but not why you would want to do this. In particular, I would think in most situations you wouldn’t want the result flattened. What are more practical examples where this behavior neatly solves your problem? (whereas the undocumented use of ap when both Apply’s are functions does make sense to me as a practical tool)

Philipp Wille
@Yord
Sep 11 2017 06:22

anytime I see converge with identity in the first position, I think "I can probably rewrite that with chain"; sure enough: chain(flip(concat), o(reverse, init))

@buzzdecafe Awesome! :D Got to remember this rule!

Jonah
@jonahx
Sep 11 2017 06:41
@Yord did you see @syaiful6’s answer: ap(concat, o(tail, reverse))
Philipp Wille
@Yord
Sep 11 2017 06:42
I did not, it is beautiful! :)
Syaiful Bahri
@syaiful6
Sep 11 2017 06:59
@jonahx if the type in question is both Applicative and Monad, we aggree that <*> = ap like in Haskell's docs say. That's why <*> defined for list is like explosive version of map. I see it like a way to construct a cartesian product. It defined that way because it should follow the type class laws that list provides eg xs >>= return = xs. return for list is return x = [x]. Not because it more practical. Of course there is also a reasonable way of applying a list of functions, that do like zipWith, and pure/return is defined as create an infinite list by repeating the element. By doing so you can't make it a Monad, just an Applicative.
Jonah
@jonahx
Sep 11 2017 07:06

@syaiful6 Thanks. Re: this point:

It defined that way because it should follow the type class laws that list provides eg xs >>= return = xs. return for list is return x = [x]. Not because it more practical.

I understand that in many cases the laws dictate how it must work, but that just begs the question: why these laws? presumably, the answer is that people have noticed these algebraic structures are high-level patterns that appear again and again in diverse applications, and so we codify and study them. Now, if the behavior of ap of a list of functions and a list of values is just a curious artificat of the Apply laws (which are only useful in other contexts), why bother implementing it and documenting it? I have to believe there are common real-world use cases or it wouldn’t have been added to ramda.

But maybe your cartesian product use-case is enough?
Syaiful Bahri
@syaiful6
Sep 11 2017 07:08
@jonahx take a look of haskell list comprehension, that syntax actually can be implemented using the Monad + MonadPlus instance of List.
Haskell programmer love using that comprehension, Purescripter can imitate it using the Monad + MonadPlus of List alone. What a joy!
Jonah
@jonahx
Sep 11 2017 07:27
@syaiful6 thanks again
Michael Hurley
@buzzdecafe
Sep 11 2017 10:07
@syaiful6 your ap-based implementation is beautiful! :+1:
Kurt Milam
@kurtmilam
Sep 11 2017 10:15
:+1:
I've learned a lot from this exercise. Here's the REPL with the ap version of mirror and mirrorPivot. Thanks again for your help, @syaiful6!
Kurt Milam
@kurtmilam
Sep 11 2017 10:21
@jonahx I went looking for places I'm using R.ap( fns )( xs ) in some code I'm working on. In the ones I found, xs.length was always 1, and I often explicitly converted an x to xs with R.of, meaning that juxt was a better solution in all the examples. So I replaced them all with juxt, removed a few lines of code from my codebase and no longer have any examples of R.ap( fns )( xs ) to share :D
I was hoping to find in my code a good, real-world example of where using R.ap( fns )( xs ) made sense, but I'm afraid I've come up empty-handed at this time.
Adam Szaraniec
@mimol91
Sep 11 2017 11:30

Hey, I am trying to understand what is a reason that in ramda source function is always wrapped with curry.
For example

module.exports = _curry1(function always(val) {
  return function() {
    return val;
  };
});

What is reason to use curry1 instead of returning inner function?

Kurt Milam
@kurtmilam
Sep 11 2017 12:21
@mimol91
const fn = R.always()
fn()()()(1)() //-> 1
I think it's easier to understand if you start with functions that have arity>1, then realize that unary functions like always are wrapped in _curry1 to maintain consistency with the other functions.
Adam Szaraniec
@mimol91
Sep 11 2017 12:28
Thanks,didnt tought about it
Kurt Milam
@kurtmilam
Sep 11 2017 12:28
Sure. If you still have questions, feel free to ask!
Alec
@alavkx
Sep 11 2017 14:02
Is there a better way to retrieve data from a different dataset from the one passed?
R.map(x => cache[x].data))
Kurt Milam
@kurtmilam
Sep 11 2017 14:10
@alavkx R.map( R.path( [ x, 'data' ], cache ) ) is a point-free version of your code, if that's what you're looking for.
Is xs an array of all of the keys in cache?
Alec
@alavkx
Sep 11 2017 14:20
Correct
xs is a set of objects each with an id. Cache contains a reverse map of the object for faster lookups
Assuming this would work?
const getDataById = R.map( R.path( [ x, 'data' ] )
getDataById(cache)
Kurt Milam
@kurtmilam
Sep 11 2017 14:25
No, that won't do the trick.
Alec
@alavkx
Sep 11 2017 14:26
Ah my mistake, xs is the set of ID's
I think what I'm looking for is something along the lines of...
const getDataById = R.map( R.path( [ R.identity, 'data' ] )
Kurt Milam
@kurtmilam
Sep 11 2017 14:36
Sample data plus desired output in the REPL would be helpful.
Alec
@alavkx
Sep 11 2017 14:36
Sure thing one moment
Kurt Milam
@kurtmilam
Sep 11 2017 14:37
I've started one here that may be useful.
@alavkx But it would be better if I knew the sample data was right, and I knew how the desired output should look.
Alec
@alavkx
Sep 11 2017 14:50
I was writing out an example but it got very contrived due some complexity im trying to leave out
Kurt Milam
@kurtmilam
Sep 11 2017 14:51
Is my example REPL a decent simplification?
Alec
@alavkx
Sep 11 2017 14:51
Your example looks correct, except ids will not be known until execution
it is derived from a composition operation
Kurt Milam
@kurtmilam
Sep 11 2017 14:52
And does the result look correct?
Alec
@alavkx
Sep 11 2017 14:53
yes :)
Kurt Milam
@kurtmilam
Sep 11 2017 14:54
Does it have to be point free?
Alec
@alavkx
Sep 11 2017 14:54
Thats the goal
image.png
That leaves a lot out, but a bit more context of how it currently looks
I'm not using ramda but assume fp has more or less the same type signatures
Kurt Milam
@kurtmilam
Sep 11 2017 14:58
REPL
const getFromCache =
  o( o( pluck( 'data' ) ) )
   ( flip( props ) )

getFromCache( cache )( ids ) //-> [ 1, 3 ]
If you're not using Ramda, you may want to create some of those functions on your own, for reuse.
Alec
@alavkx
Sep 11 2017 15:00
Ooh well done ha
I was hoping there was some way to set something lenslike to a specific object
props is very useful, havent used that before
Kurt Milam
@kurtmilam
Sep 11 2017 15:02
If you want to work with lenses, and don't mind bringing in another library, I would suggest taking a look at partial.lenses.
You can ask questions about partial.lenses in the calmm-js gitter. I'm a big fan of partial.lenses.
Alec
@alavkx
Sep 11 2017 15:03
I'll take a look. I haven't conquered the more advanced lense concepts quite yet
been meaning to
Kurt Milam
@kurtmilam
Sep 11 2017 15:04
partial.lenses has a ton of useful functionality - really nice library for learning lenses, in my opinion.
Alec
@alavkx
Sep 11 2017 15:05
The documentation looks great
Thanks for the help Kurt :)
Kurt Milam
@kurtmilam
Sep 11 2017 15:05
You're welcome! Good luck!
EmilLindfors
@EmilLindfors
Sep 11 2017 16:50
Hey guys!
I have an array of numbered objects where I delete a certain object. How do I decrease the number prop on all the objects after the deleted one to go from 1,3,4,5 to 1,2,3,4? I was thinking about some kind of split and dec, but i didnt manage to join the arrays again. https://goo.gl/Aorc6T
Brad Compton (he/him)
@Bradcomp
Sep 11 2017 16:54
@EmilLindfors Will they always be increasingly ordered starting at 1?
EmilLindfors
@EmilLindfors
Sep 11 2017 16:55
yes, that is the plan at least :)
Brad Compton (he/him)
@Bradcomp
Sep 11 2017 16:56
Like this :question:
EmilLindfors
@EmilLindfors
Sep 11 2017 16:58
@Bradcomp perfect, thank you so much!
Julian Coleman
@juliancoleman
Sep 11 2017 19:14
Could I get some help with a pretty hectic data transformation?
Jonah
@jonahx
Sep 11 2017 19:38
@juliancoleman go ahead and post, usually someone will answer
Julian Coleman
@juliancoleman
Sep 11 2017 19:41

I'm trying to get my data from this:

[{
  first_name: "Bob",
  last_name: "Test",
  email_address: "bob@test.com",
  uid: "qwertyuiop",
}]

into this

{
  qwertyuiop: {
    first_name: // ...
  }
}
And I want to do this in a reusable, ramda-esque way
It should omit the uid from the product as well
pankaj-pp
@pankaj-pp
Sep 11 2017 19:59
const data = [{
  first_name: "Bob",
  last_name: "Test",
  email_address: "bob@test.com",
  uid: "qwertyuiop",
}]

const getData = R.compose(
  R.map(
    R.converge(R.objOf, [
      R.prop('uid'),
      R.omit('uid')
    ])
  )
)
getData(data)
@juliancoleman is this what you needed?
Julian Coleman
@juliancoleman
Sep 11 2017 20:01
Pretty close! So the purpose is to transform an array into an object entirely. I find myself using this way too much to keep forgetting. My collections come back as arrays, so I'm trying to create a hashmap based on the id from the data I received
I really admire this implementation
Kurt Milam
@kurtmilam
Sep 11 2017 20:02
const a2o = 
  o( fromPairs )
   ( map( juxt( [ prop( 'uid' ), omit( 'uid' ) ] ) ) )
REPL - should do the trick.
Julian Coleman
@juliancoleman
Sep 11 2017 20:03
@kurtmilam this implementation works! It's a bit confusing primarily from o and juxt, but I'll read up on why this works. Thanks a bunch, man
Kurt Milam
@kurtmilam
Sep 11 2017 20:04
No problem! o is a variation on compose. juxt is a variation on ap.
Julian Coleman
@juliancoleman
Sep 11 2017 20:04
Holy hell. That is gorgeous
Kevin Wallace
@kedashoe
Sep 11 2017 20:04
there is also indexBy
something like https://goo.gl/bQeebN
Julian Coleman
@juliancoleman
Sep 11 2017 20:05
This implementation is actually fairly straightforward
I didn't see indexBy
Kurt Milam
@kurtmilam
Sep 11 2017 20:05
@kedashoe thanks for sharing indexBy. I don't think I've ever used it before.
Emilio Srougo
@emilio_srg_twitter
Sep 11 2017 20:06
Is there a way to use lenses safely? for example if I run over(arrayLens, map(negate)) and the array is not there, I don't want a runtime error
Julian Coleman
@juliancoleman
Sep 11 2017 20:07
lenses are safe. It always returns a new copy, if that's what you're asking. The setter should not mutate the data structure.
ah, I didn't read fully.
Kevin Wallace
@kedashoe
Sep 11 2017 20:08
@kurtmilam :beers:
Emilio Srougo
@emilio_srg_twitter
Sep 11 2017 20:11
yes @juliancoleman I mean safety in case the prop or path of the lens is not in the object
Emilio Srougo
@emilio_srg_twitter
Sep 11 2017 20:29
This is the best I came up with:
ifElse(view(arrayLenses), over(arrayLenses, map(negate)), identity)
Ideally, I would like over to do nothing if the lens returns undefined. Or maybe be able to specify a default value when creating the lens.
Kurt Milam
@kurtmilam
Sep 11 2017 20:34
@emilio_srg_twitter if you want a very powerful lens library, I recommend partial.lenses. You can ask questions about the library in the calmm-js Gitter channel.
Having said that, I think you can move your ifElse inside the function you pass to over.
Something like this may work:
over( arrayLenses )
    ( unless( isNil )
            ( map( negate ) )
    )
Emilio Srougo
@emilio_srg_twitter
Sep 11 2017 20:40
@kurtmilam Yeah that's definitely cleaner. Will check that library. Thanks
Kurt Milam
@kurtmilam
Sep 11 2017 20:41
You can swap out unless( isNil ) with when( is( Array ) ) if you want to make sure you only map over arrays.
Emilio Srougo
@emilio_srg_twitter
Sep 11 2017 20:49
@kurtmilam :thumbsup:
Michael Hurley
@buzzdecafe
Sep 11 2017 22:39
@kurtmilam you are the juxt master