These are chat archives for ramda/ramda

4th
Dec 2016
Hardy Jones
@joneshf
Dec 04 2016 00:00
Shitty types though...
Hmm. Sounds like it's not goig to happen in ramda.
James Forbes
@JAForbes
Dec 04 2016 00:01
So I'm stuck on why reduce needs to be ordered anyway? If the resulting type isn't ordered, and the input type isn't ordered, and equality ignores order, why does it matter?
Brad Compton (he/him)
@Bradcomp
Dec 04 2016 00:01
But the resulting type of reduce is often ordered
James Forbes
@JAForbes
Dec 04 2016 00:02
Oh wait, I guess you might have unordered in, ordered out yeah
Bradcomp @Bradcomp considering creating a static land object library
James Forbes
@JAForbes
Dec 04 2016 00:05
I suppose you could inject fantasyland/map fantasyland/ap etc on the object prototype in your own projects and ramda would just accept it. Barring all the scenarios where that is a horrible idea, it works for me in some contexts where I own the environment.
Yeah static would be a lot less messy
Hardy Jones
@joneshf
Dec 04 2016 00:05
It depends on what the function is.
If the function is commutative, it doesn't matter.
Brad Compton (he/him)
@Bradcomp
Dec 04 2016 00:07
Honestly, the most common scenario I run into is the Map of Applicatives to Applicative of Map case, which is unordered
Hardy Jones
@joneshf
Dec 04 2016 00:07
But note that reduce itself doesn't force the ordering.
Brad Compton (he/him)
@Bradcomp
Dec 04 2016 00:08
True
James Forbes
@JAForbes
Dec 04 2016 00:09
Kind of don't want to open an issue considering how many times its been brought up
Brad Compton (he/him)
@Bradcomp
Dec 04 2016 00:14
Yeah... composing with toPairs or values isn't too onerous depending on what you need.
Neither of which solve the issue of ordering though :stuck_out_tongue:
Hardy Jones
@joneshf
Dec 04 2016 00:15
Throw a sortBy in the mix.
And add it to the cookbook. :)
James Forbes
@JAForbes
Dec 04 2016 00:55

I think @Bradcomp is on the right track with a static library, maybe something like Obj = {map,ap,sequence,traverse}

So @m59peacemaker's problem would be able to be solved like:

const toFuture = unless( is(Future), Future.of )

const obj = {
  foo: 1,
  bar: 'abc',
  qux: Future.of('qux')
}

// SomeObject -> Future SomeOtherObject
const f = pipe(
  R.over(
    R.lensProp('foo'),
    R.filter(R.has('bar'))
  )  // { foo: [{ bar: 1 }], qux: 'abc']}
  ,R.over(
    R.lensProp('qux'),
    () => Future.of('def') // async transform
  )  // { foo: [{ bar: 1 }], qux: Future('def') }
  ,Obj.map(toFuture) // { foo: Future([bar:1]), qux: Future('def') }
  ,Obj.sequence(Future.of) // Future( {foo: [bar:1 ], qux: 'def' }) 
)
Johnny Hauser
@m59peacemaker
Dec 04 2016 00:56
That's a bit of two subjects, I think.

@Bradcomp's function:

const over = R.curry((lens, f, v) => R.map( // map over the functor
  // "newVal" is the value contained in the functor
  newVal => R.set(lens, newVal, v), // the object with the lens set to the new value
  f(R.view(lens, v)) // functor containing new value
)

is better for my use case.

but the Obj library would be sweet!
James Forbes
@JAForbes
Dec 04 2016 01:01
@m59peacemaker yeah that's cool, what would the usage be though? Don't we end up with a property that is a future still? (again which is completely valid)
If I understand correctly, f in your example would be transformQux so now we'd have a Future inside a Future
@m59peacemaker I just added some comments to the above to illustrate what's going on with sequence
Johnny Hauser
@m59peacemaker
Dec 04 2016 01:11
Nope, the result is exactly the same as yours
over gives you a function that takes an object and returns a functor containing that object, so you're right about that
but, the value set is not that functor, it's the actual value
It's brilliant
Johnny Hauser
@m59peacemaker
Dec 04 2016 01:19
const over = R.curry((lens, f, v) => R.map( // map over the future (lol that's a funny thing to say)
  // "newVal" is the value of the future, right now, that value is for just the lensed data
  newVal => R.set(lens, newVal, v), // what we return here is the new value inside the future, which we want to be the whole object, input the object, set the lens to its new value, return the new object!
  f(R.view(lens, v)) // get a future representing the future value to be set to the lens
)
@JAForbes There's that mouthful in case it helps
James Forbes
@JAForbes
Dec 04 2016 01:24
haha I'm still not getting it, can you show me the usage?
Johnny Hauser
@m59peacemaker
Dec 04 2016 01:25
It's easier to understand use pipe so it's in order
R.pipe(
  R.over(R.lensProp('foo'), R.filter(R.has('bar'))),
  over(
    R.lensPath(['foob', 'bass']),
    v => incLater(500, v)
  ),
  R.map( // now dealing with a future, have to map it
    R.assoc('qux', 'def')
  )
)(data)
.fork( //etc
Johnny Hauser
@m59peacemaker
Dec 04 2016 01:32

const over = R.curry((lens, f, v) => R.pipe(
  R.always(v),
  R.view(lens), // initial value of the lensed data
  f, // new value for the lens inside a functor
  R.map( // map over the functor to access and transform its value
    newVal => R.set(lens, newVal, v) // take whole object, set the lens to newVal, return new whole object
  )
)())
James Forbes
@JAForbes
Dec 04 2016 01:32
wait I'm decoding it :)
yeah I get it :D
Johnny Hauser
@m59peacemaker
Dec 04 2016 01:34
I'm glad it's not just me haha.
James Forbes
@JAForbes
Dec 04 2016 01:34

I think if v was called obj I would have got it sooner

const over = R.curry((lens, f, obj) => R.map( 
  v => R.set(lens, v, obj),
  f(R.view(lens, obj))
)

Is that right still?

const over = R.curry((lens, f, obj) => 
// 2. we then map over the future so we can turn that future of a property, into a future of the entire object
R.map( 
  // 3. v is the value within the future returned by f
  // we use R.set to place that value inside the object 
  // because this is all in a call to .map, we end up with a Future obj
  v => R.set(lens, v, obj),
  // 1. This grabs the property at the path on the obj, passes it to f, which returns a future
  f(R.view(lens, obj))
)
That's bloody genius @Bradcomp @m59peacemaker !
Brad Compton (he/him)
@Bradcomp
Dec 04 2016 01:39
:tophat: :sparkles: :smile:
James Forbes
@JAForbes
Dec 04 2016 01:39
Man lenses are sweet!
Brad Compton (he/him)
@Bradcomp
Dec 04 2016 01:39
I think it might be the case that lenses are supposed to do that for us, but we'll see....
TBH this is the most compelling use for lenses I've seen.
Johnny Hauser
@m59peacemaker
Dec 04 2016 01:41
It does stand to reason that a functor would always be at the top level
but I know next to nothing about anything :D
James Forbes
@JAForbes
Dec 04 2016 01:42

The lens acts to parameterize the path so we don't need to know about it.
But it is way better than that because the lens isn't necessarily a path, it could be anything.

But we could kind of do this with R.path / R.assocPath which is less cool, but might help me grasp it

const over = R.curry((path, f, obj) => 
  R.map( 
    v => R.assocPath( path, v, obj),
    f( R.path(path, obj) )
  )

Is that right?

Brad Compton (he/him)
@Bradcomp
Dec 04 2016 01:43
Yes!
James Forbes
@JAForbes
Dec 04 2016 01:43
ok now I officially get it I think
that is such a great demo of lenses
And I like path / assocPath, but it makes you wonder if we even need them
I don't know why, but this function questions my notions of what is an appropriate use of monad's. Aren't we breaking a contract here by using the object from the closure and avoiding using chain?
I guess in a pure context it doesn't matter, but obj might change while the Future is resolving making it impure
Is that wrong?
Johnny Hauser
@m59peacemaker
Dec 04 2016 01:47
@JAForbes So, one thing I just remembered, assoc and assocPath use lenses underneath. They're just shortcuts.
James Forbes
@JAForbes
Dec 04 2016 01:47
They use lenses in the implementation, isn't that slower?
Its cool though
I guess assoc already copies the object which is the slowest part probably
Johnny Hauser
@m59peacemaker
Dec 04 2016 01:48
yep
James Forbes
@JAForbes
Dec 04 2016 01:50
Still wondering about the impure aspect
Johnny Hauser
@m59peacemaker
Dec 04 2016 01:50
I didn't follow the chain comment
Brad Compton (he/him)
@Bradcomp
Dec 04 2016 01:52
@JAForbes you're right that the object could change in the case of a Future, but it shouldn't if you're FP'ing right. You could avoid the closure (I think) by wrapping the object and using ap, but you would need to know what to wrap it in - which makes a case for putting of on the prototype
James Forbes
@JAForbes
Dec 04 2016 01:52
yeah its kind of only a problem if you are writing impure code elsewhere
my concerns are probably not worth worrying about @m59peacemaker
Johnny Hauser
@m59peacemaker
Dec 04 2016 01:53
I worry about errrthing
I'm tired of bugs.
James Forbes
@JAForbes
Dec 04 2016 01:54
well it would only matter if some other process had a reference to that object and mutated it, and even then it might not matter in your usecase
But technically that function could return different values given the same inputs based on the state of the environment
Johnny Hauser
@m59peacemaker
Dec 04 2016 01:54
Oh, if you meant as far as having a practical effect, yeah, no worries there
But I will definitely worry over the technicality, even if it never affects anything
James Forbes
@JAForbes
Dec 04 2016 01:55
Yeah I can imagine some cases where it might have an unintended side affect
Alright that was great! I'm going to get back to work :) thanks for teaching me that @m59peacemaker @Bradcomp :sparkles:
Johnny Hauser
@m59peacemaker
Dec 04 2016 02:11
np!
Brad Compton (he/him)
@Bradcomp
Dec 04 2016 02:29
@ram-bot
const over_ = R.curry((lens, f, obj) => {
  const functor = f(view(lens, obj));
  return lift(set(lens))(functor)(functor.of(obj))
});


const f = ifElse(isNil, Maybe.Nothing, Maybe.of)

over_(lensProp('qux'), f, {qux: 'qux'})
ram-bot
@ram-bot
Dec 04 2016 02:29
_Just { value: { qux: 'qux' } }
Brad Compton (he/him)
@Bradcomp
Dec 04 2016 02:30
Please note that this version won't work with Fluture, due to incompatibilities in the FL version used there with the version assumed by R.lift
It also assumes that of is on the prototype
Johnny Hauser
@m59peacemaker
Dec 04 2016 02:32
what's the advantage?
just more appropriate than map with the anonymous function?
Brad Compton (he/him)
@Bradcomp
Dec 04 2016 02:34
Not really any advantage, just different
It wraps up the object in the same functor on the spot
Instead of pulling it in from the outside after the fact
all of this is metaphorical of course ;)
Johnny Hauser
@m59peacemaker
Dec 04 2016 02:36
And it isn't mutable once in the functor?
Brad Compton (he/him)
@Bradcomp
Dec 04 2016 02:36
It still is, unfortunately
Johnny Hauser
@m59peacemaker
Dec 04 2016 02:36
:'(
Brad Compton (he/him)
@Bradcomp
Dec 04 2016 02:36
That's just JS semantics for you :-P
Johnny Hauser
@m59peacemaker
Dec 04 2016 02:36
yeah
Brad Compton (he/him)
@Bradcomp
Dec 04 2016 02:37
My variable is named wrong :cry: - functor should be named applicative
cuz we're using ap and of
So, now that we're discussing it, seems like the only advantage this version has is to satisfy certain aesthetic preferences.
Hardy Jones
@joneshf
Dec 04 2016 02:44
I'm confused. Is the over provided above different from R.over?
Also, isn't R.set implemented in terms of R.over?
Brad Compton (he/him)
@Bradcomp
Dec 04 2016 02:45
There are two type sigs on over, but it appears only the first is implemented
Lens s a = Functor f => (a → f a) → s → f s
Ramda's over doesn't actually do this :(

Also, isn't R.set implemented in terms of R.over?

yes

Hardy Jones
@joneshf
Dec 04 2016 02:47
That's the definition of Lens s a.
Brad Compton (he/him)
@Bradcomp
Dec 04 2016 02:47
@ram-bot
over(
//Lens s a
lensProp('qux'), 
//a -> f a
Maybe.of, 
//s
{qux: 1}
)
ram-bot
@ram-bot
Dec 04 2016 02:47
{ qux: _Just { value: 1 } }
Brad Compton (he/him)
@Bradcomp
Dec 04 2016 02:47
:point_up_2: I took the def from there
Hardy Jones
@joneshf
Dec 04 2016 02:48
I mean there's a signature for over and a signature for Lens s a.
Brad Compton (he/him)
@Bradcomp
Dec 04 2016 02:48
Oh dammit
NOW I understand what I was missing :(
Hardy Jones
@joneshf
Dec 04 2016 02:48
You could rewrite those two lines into one: (forall f. Functor f => (a → f a) → s → f s) -> (a -> a) -> s -> s.
YEah, it's a little confusing
But I guess what you wrote as over above is a lens?
Brad Compton (he/him)
@Bradcomp
Dec 04 2016 02:51
I guess so, let's try ;)
Nope...
What I wrote was over_ :: Lens s a -> (a -> f a) -> s -> f s
With the same Functor f constraint
derp
over_ :: Functor f => Lens s a -> (a -> f a) -> s -> f s
Johnny Hauser
@m59peacemaker
Dec 04 2016 02:56
WOOT! I can read these now!
Brad Compton (he/him)
@Bradcomp
Dec 04 2016 03:00
:scream_cat:
@ram-bot
const headLens = lensIndex(0)
const maybeReturner = ifElse(isNil, Maybe.Nothing, compose(Maybe.Just, inc))
headLens(maybeReturner)([1, 2, 3])
ram-bot
@ram-bot
Dec 04 2016 03:01
_Just { value: [ 2, 2, 3 ] }
Brad Compton (he/him)
@Bradcomp
Dec 04 2016 03:01
Just leave out over and use the Lens directly!!!!
@joneshf Thank you for forcing me to go back over the signature.
Johnny Hauser
@m59peacemaker
Dec 04 2016 03:02
How 'bout that.
I'm going to dissect that and comment it up. I'll post the laymen explanation here.
What's the preferred package to get Maybe?
Brad Compton (he/him)
@Bradcomp
Dec 04 2016 03:06
@m59peacemaker It can be incredibly enlightening to read the type sigs - as was just demonstrated ;)
Johnny Hauser
@m59peacemaker
Dec 04 2016 03:06
Glad I just learned to do it =D
Brad Compton (he/him)
@Bradcomp
Dec 04 2016 03:06
Ramda-Fantasy is the one Ram-Bot uses...
I've used folktale's Data.Maybe
If you are interested in a library that does strong run time type checking and also has these structures, I would encourage you to check out Sanctuary
Johnny Hauser
@m59peacemaker
Dec 04 2016 03:08
I read through a lot of its docs and read an article about it, but it is beyond me still.
Brad Compton (he/him)
@Bradcomp
Dec 04 2016 03:16
Well, both of the others are good choices. R-F has all the structures in one package (Maybe, Either, Tuple, Future, maybe others...)
Really I was just using Maybe as an example though. The exact same code would work with a futureReturner function :-D
Johnny Hauser
@m59peacemaker
Dec 04 2016 03:28
yeah, I just figured I might as well use that example for the diverse learning experience
Hardy Jones
@joneshf
Dec 04 2016 03:30
Does @ram-bot have sanctuary?
Johnny Hauser
@m59peacemaker
Dec 04 2016 03:37
@Bradcomp why wouldn't this work the same? R.lensIndex(0, maybeReturner)([1, 2, 3])
It returns [Function]
I don't see the difference
Brad Compton (he/him)
@Bradcomp
Dec 04 2016 03:39
@ram-bot
S.inc(1)
ram-bot
@ram-bot
Dec 04 2016 03:39
2
Brad Compton (he/him)
@Bradcomp
Dec 04 2016 03:39
@joneshf yes!
Johnny Hauser
@m59peacemaker
Dec 04 2016 03:40
@ram-bot
const maybeReturner = ifElse(isNil, Maybe.Nothing, compose(Maybe.Just, inc))
lensIndex(0, maybeReturner)([1, 2, 3])
ram-bot
@ram-bot
Dec 04 2016 03:40
[Function]
Johnny Hauser
@m59peacemaker
Dec 04 2016 03:41
@ram-bot
const maybeReturner = ifElse(isNil, Maybe.Nothing, compose(Maybe.Just, inc))
lensIndex(0)(maybeReturner)([1, 2, 3])
ram-bot
@ram-bot
Dec 04 2016 03:41
_Just { value: [ 2, 2, 3 ] }
Johnny Hauser
@m59peacemaker
Dec 04 2016 03:41
grrrrrr
Brad Compton (he/him)
@Bradcomp
Dec 04 2016 03:41
@m59peacemaker lensIndex only takes a single parameter, and returns a lens. SO when you pass it two, it just ignores the second one
Johnny Hauser
@m59peacemaker
Dec 04 2016 03:42
darnit, brain.
Thanks
Johnny Hauser
@m59peacemaker
Dec 04 2016 04:09
JavaScript functions aren't functors, but Ramda treats them like they are by making the function itself its map. Am I right?
const foo = v => v <-- not a functor, but Ramda treats it kind of like const foo = {map: v => v} when you try to map over it
Brad Compton (he/him)
@Bradcomp
Dec 04 2016 04:11
map(inc, inc)(1)
@ram-bot
map(inc, inc)(1)
ram-bot
@ram-bot
Dec 04 2016 04:12
3
Brad Compton (he/him)
@Bradcomp
Dec 04 2016 04:12
It treats map like compose I think...
@ram-bot
map(x => x * 2, inc)(1)
ram-bot
@ram-bot
Dec 04 2016 04:13
4
Johnny Hauser
@m59peacemaker
Dec 04 2016 04:13
Lens s a = Functor f => (a → f a) → s → f s
I'm referring to that
you can pass a function where it says to pass a functor (and usually do pass a function)
Brad Compton (he/him)
@Bradcomp
Dec 04 2016 04:14
Functor f is a type constraint, where (a → f a) is the function you pass in.
Johnny Hauser
@m59peacemaker
Dec 04 2016 04:15
oh crud. =>
Brad Compton (he/him)
@Bradcomp
Dec 04 2016 04:15
So : for any typeclass f that is a Functor (has a map), the lens takes a function from a to f a, and an s, and returns an f s
Yeah, it's subtle
Johnny Hauser
@m59peacemaker
Dec 04 2016 04:16
Sigh. I can be annoying. I'm some kind of unknown and persistent sick. Lots of brain fog all the time. Sorry about that.
Brad Compton (he/him)
@Bradcomp
Dec 04 2016 04:16
No need to apologize. it takes a while
Johnny Hauser
@m59peacemaker
Dec 04 2016 04:17
I just hate making dumb mistakes. I know the difference between being inexperienced and being spaced out.
thanks a ton
James Forbes
@JAForbes
Dec 04 2016 04:20
@m59peacemaker your not annoying, its important that asking questions is never deemed annoying :)
Brad Compton (he/him)
@Bradcomp
Dec 04 2016 04:20
Agreed! If we didn't like answering questions we just wouldn't answer
James Forbes
@JAForbes
Dec 04 2016 04:20
If it were, I think we'd all be worse for it
Johnny Hauser
@m59peacemaker
Dec 04 2016 04:21
Sweet! This is one swell community.
Brad Compton (he/him)
@Bradcomp
Dec 04 2016 04:24
TBH, I learned a lot today through working with you on this stuff. It would have been a bummer if you didn't ask.
James Forbes
@JAForbes
Dec 04 2016 04:27
Same
Johnny Hauser
@m59peacemaker
Dec 04 2016 04:27
I'm feeding all this knowledge to some programming friends, btw :)
James Forbes
@JAForbes
Dec 04 2016 04:28
That is a valuable skill
Johnny Hauser
@m59peacemaker
Dec 04 2016 04:28
They're all much more competent and experienced developers than I, but this is largely new to them as well.
Travis LaDuke
@laduke
Dec 04 2016 05:36
Drawing a blank on this one: Location: 40.251N 73.164W -> ['Location', '40.251N 73.164W']
Johnny Hauser
@m59peacemaker
Dec 04 2016 05:40
what's the goal?
Oh, that's your input / output?
your demo is different
nm, maybe I see what you mean now
Travis LaDuke
@laduke
Dec 04 2016 05:42
demo not working
Johnny Hauser
@m59peacemaker
Dec 04 2016 05:42
those are all sample input, I think is what you mean
Travis LaDuke
@laduke
Dec 04 2016 05:43
yes
Johnny Hauser
@m59peacemaker
Dec 04 2016 05:52
I'd do it like this @laduke R.match(/^(\w+): ([\d\.]+)\w ([\d\.]+)\w/)(a)
"Location", "40.251", "73.164"
Travis LaDuke
@laduke
Dec 04 2016 05:53
That's kinda what I just landed on
Johnny Hauser
@m59peacemaker
Dec 04 2016 05:54
I thought something notified me of a message from you saying something about match, but I don't see it now
Travis LaDuke
@laduke
Dec 04 2016 05:54
I deleted it when I couldn't get rambot to work
Johnny Hauser
@m59peacemaker
Dec 04 2016 05:54
oh :)
mine doesn't work with your other data, though, but that's because I went too specific
There's a cool thing for this
If you need hardcore power, some kind of tokenizer
Travis LaDuke
@laduke
Dec 04 2016 05:56
Not super happy about this but:
const splitter = str => {
  var arr = R.match(/^(.*): (.*$)/)(str);
  return [arr[1], arr[2]];
}
^tokenizer might be a little overkill here ;)
Johnny Hauser
@m59peacemaker
Dec 04 2016 05:58
yeah haha
Just sayin'. Opportunity to mention a tokenizer hardly ever comes up. :)
const splitter = R.pipe(R.match(/^(.*): (.*$)/), R.slice(1, 3))
I wonder if an Either or Maybe is appropriate there
Johnny Hauser
@m59peacemaker
Dec 04 2016 06:04
I haven't figured those out yet
Travis LaDuke
@laduke
Dec 04 2016 06:08
I probably should wrap some of this up... I get it working
I need a function like ...rest now
Travis LaDuke
@laduke
Dec 04 2016 06:13
const splitter = R.pipe(
    R.match(/^(.*): (.*$)/),
    R.slice(1,3)
 )

R.objOf(...splitter(b))
Johnny Hauser
@m59peacemaker
Dec 04 2016 06:14
I feel like lift does that
but that is seriously just a feeling with no logical understanding behind it =D
Travis LaDuke
@laduke
Dec 04 2016 06:16
haha, that's what i was just guessing
const splitter = R.pipe(
    R.match(/^(.*): (.*$)/),
    R.slice(1,3),
    R.apply(R.objOf)
 )
Johnny Hauser
@m59peacemaker
Dec 04 2016 06:18
ah yeah
Travis LaDuke
@laduke
Dec 04 2016 06:18
whew
Johnny Hauser
@m59peacemaker
Dec 04 2016 06:18
lift is almost the opposite hah
Travis LaDuke
@laduke
Dec 04 2016 06:22
the regex looks like the table flip ascii art almost.
Johnny Hauser
@m59peacemaker
Dec 04 2016 06:22
lol
Tomáš Konrády
@tommmyy
Dec 04 2016 12:39
Hello, do you think that useWithMulti is useful? Or is there better solution? thanks
const useWithMulti = R.curry(
  (fn, transformers, x) => R.useWith(
    fn, 
    transformers 
  )(...R.repeat(x, R.length(transformers)))
);

useWithMulti(R.assoc('x'), [R.prop('y'), R.identity])({ y: 1 });

// pointless:
// ((x) => R.assoc('x', x.y, x ))({ y: 1 })
Johnny Hauser
@m59peacemaker
Dec 04 2016 14:14
What are you trying to do? I don't understand it.
Tomáš Konrády
@tommmyy
Dec 04 2016 16:05
@m59peacemaker calculate new property of the object based on other properties of the same object in point-free way
Kurt Milam
@kurtmilam
Dec 04 2016 16:53
I wonder whether it could be helpful to display the first argument to _arity in the error that is thrown when the first argument is something other than a non-negative integer no greater than ten.
Brad Compton (he/him)
@Bradcomp
Dec 04 2016 17:02
R.converge
Brad Compton (he/him)
@Bradcomp
Dec 04 2016 17:02
@tommmyy Check out converge :-D
Travis LaDuke
@laduke
Dec 04 2016 17:22
:metal:
Brad Compton (he/him)
@Bradcomp
Dec 04 2016 17:24
@ram-bot
converge(assoc('x'), [prop('y'), identity])({y: 5});
ram-bot
@ram-bot
Dec 04 2016 17:24
{ y: 5, x: 5 }
Tomáš Konrády
@tommmyy
Dec 04 2016 17:58
@Bradcomp ah, super. So many functions in Ramda... :D
Kurt Milam
@kurtmilam
Dec 04 2016 18:32
I'm looking for a more detailed explanation of lift than what the documentation offers. Can anyone point me to a good resource?
In my quest to speed up development with Ramda, I've decided to take a break and spend a little time implementing a few functions that I sometimes have trouble with, where I don't always understand why something I've tried isn't working. I've started with curry and partial, and lift is next on my list.
I'm trying to implement each function by researching the concept online until I feel that I have a good understanding of it, without looking Ramda (or anyone else's) source, then writing my own function that accomplishes the same goal.
Brad Compton (he/him)
@Bradcomp
Dec 04 2016 18:48

@kurtmilam lift is tricky because it performs differently depending on what you pass to it. So it works a certain way for Arrays, another way for Function, and another way if you pass it Applicatives.

This isn't entirely accurate though, because it's actually just treating the Functions or Arrays as Applicatives.

So to understand lift it really helps to understand Functor and Applicative - i.e. map and ap.

http://adit.io/posts/2013-04-17-functors,_applicatives,_and_monads_in_pictures.html#applicatives
https://drboolean.gitbooks.io/mostly-adequate-guide/content/ch10.html (of course, there's background to know first here...)

Denis Stoyanov
@xgrommx
Dec 04 2016 18:49
3 day of http://adventofcode.com/2016/day/3
R.compose(
  R.lift((part1, part2) => ({part1, part2}))(
    R.compose(R.length, R.filter(xs => { let [x, y, z] = R.sort(R.subtract, xs); return x + y > z })),
    R.compose(R.compose(R.length, R.filter(xs => { let [x, y, z] = R.sort(R.subtract, xs); return x + y > z })), R.chain(R.splitEvery(3)), R.transpose)
  ),
  R.map(R.compose(R.map(x => parseInt(x, 10)), R.match(/\d+/g))),
  R.split('\n')
)(input)
Kurt Milam
@kurtmilam
Dec 04 2016 19:14
Thanks, reading.
Johnny Hauser
@m59peacemaker
Dec 04 2016 21:06
Oh my, applicatives are hard to understand.
Denis Stoyanov
@xgrommx
Dec 04 2016 21:26
@m59peacemaker I don't think so) Just apply lifted function and lifted values via unpacking it
Johnny Hauser
@m59peacemaker
Dec 04 2016 21:41
well, when you say it like that, it makes perfect sense
but I'm assuming there's a good reason Frisby wrote that section and why people read it :)
Johnny Hauser
@m59peacemaker
Dec 04 2016 22:49
@ram-bot
lensProp('foo')(compose(Maybe.Just, R.inc))({foo: 1})
ram-bot
@ram-bot
Dec 04 2016 22:49
_Just { value: { foo: 2 } }
Johnny Hauser
@m59peacemaker
Dec 04 2016 22:50
Can that be called in a different order?
Johnny Hauser
@m59peacemaker
Dec 04 2016 23:10
Is this the correct type signature of the function that is returned? compose(Maybe.Just, R.inc) // Number -> Just Number
Brad Compton (he/him)
@Bradcomp
Dec 04 2016 23:11

@m59peacemaker Almost...
The type sig is Number -> Maybe Number - even though you are returning a Just, the type is still Maybe Number

what do you mean by calling it in a different order?

Johnny Hauser
@m59peacemaker
Dec 04 2016 23:11
Like with pipe/compose?
For some reason, it's odd or confusing to me to invoke it that way
compose(Maybe.Just, R.inc), // Number -> Maybe Number
lensProp('foo'), // Lens s a = Functor f => (a → f a) → s → f s
lensProp('foo')(compose(Maybe.Just, R.inc))
Maybe I see now
s is the problem I'm having
Hardy Jones
@joneshf
Dec 04 2016 23:15
That's because the signature of lensProp is a lie.
Johnny Hauser
@m59peacemaker
Dec 04 2016 23:15
oh boy
Hardy Jones
@joneshf
Dec 04 2016 23:15
:)
Johnny Hauser
@m59peacemaker
Dec 04 2016 23:17
That's not the signature of lensProp, but the signature of the lens it returns, right?
and I'm passing compose(Maybe.Just, R.inc) where the lens wants (a -> f a)
so that's right
Brad Compton (he/him)
@Bradcomp
Dec 04 2016 23:18
R.lensProp
Hardy Jones
@joneshf
Dec 04 2016 23:18
Yeah, but the s isn't accurate
Hardy Jones
@joneshf
Dec 04 2016 23:18
You can't pass in any s
@ram-bot R.set(R.lensProp('foo'), 12, null)
ram-bot
@ram-bot
Dec 04 2016 23:18
Cannot read property 'foo' of null
Hardy Jones
@joneshf
Dec 04 2016 23:19
Though the signature says you can.
Brad Compton (he/him)
@Bradcomp
Dec 04 2016 23:19
Accessable s in Sanctuary parlance ;)
Johnny Hauser
@m59peacemaker
Dec 04 2016 23:21
@ram-bot
lensProp('foo')(
  compose(Maybe.Just, R.inc),
  {foo: 1} 
)
ram-bot
@ram-bot
Dec 04 2016 23:21
[Function]
Johnny Hauser
@m59peacemaker
Dec 04 2016 23:21
ah hah
that's what you mean, right?
That's what the type signature says should work
I got a lens, passed a -> f a and s into it, and instead of getting f s, I got a function.
Hardy Jones
@joneshf
Dec 04 2016 23:23
I don't think Accessible s helps any.
@ram-bot
const x = {};
const l = lensProp('foo');
equals(set(l, view(l, x), x), x);
ram-bot
@ram-bot
Dec 04 2016 23:23
false
Johnny Hauser
@m59peacemaker
Dec 04 2016 23:23
@ram-bot
lensProp('foo')(
  compose(Maybe.Just, R.inc),
  {foo: 1} 
)({foo: 1})
ram-bot
@ram-bot
Dec 04 2016 23:23
_Just { value: { foo: 2 } }
Johnny Hauser
@m59peacemaker
Dec 04 2016 23:24
So, is lens wrong or is the type signature wrong in the doc?
Hardy Jones
@joneshf
Dec 04 2016 23:24
Well the type signature is definitely wrong.
If the signature was more accurate, then lensProp might be a valid lens.
But given the signature it has now, it's not a lens.
I think the s needs to mention the String being passed in somehow.
Or just don't try to make it a lens to begin with.
Make it a prism or something, and be done with it.
Johnny Hauser
@m59peacemaker
Dec 04 2016 23:27
heh where do I learn what that is?
Hardy Jones
@joneshf
Dec 04 2016 23:27
Still a useful abstraction.
Still composes with lenses
though, i forget what you get when yu compose lenses and prisms.
I'm not sure where a good intro is off hand.
But.
Brad Compton (he/him)
@Bradcomp
Dec 04 2016 23:28
@m59peacemaker The trick is that the lensProp is curried, but not Ramda style curried. So you must pass the arguments in 1 at a time
Hardy Jones
@joneshf
Dec 04 2016 23:28
A lens is something that you always 100% know there is exactly one focus point.
A prism is something where you have either 0 focus points or 1 focus point, exclusively.
Johnny Hauser
@m59peacemaker
Dec 04 2016 23:30
That's odd.
Hardy Jones
@joneshf
Dec 04 2016 23:30
So, for objects, either they have a foo field (1 focus point) or they don't (0 focus points)
Brad Compton (he/him)
@Bradcomp
Dec 04 2016 23:30
it seems like, if yo urestrict the type of s, in this case {foo :: Number, ...}, then you're good, right?
Hardy Jones
@joneshf
Dec 04 2016 23:30
@Bradcomp yep!
Johnny Hauser
@m59peacemaker
Dec 04 2016 23:30
I'd think the API would ideally be consistent
Hardy Jones
@joneshf
Dec 04 2016 23:30
Well
What do you mean by consistent?
Brad Compton (he/him)
@Bradcomp
Dec 04 2016 23:31
WRT currying
I think?
So, like
R.add
Hardy Jones
@joneshf
Dec 04 2016 23:31
ah
gotcha
Brad Compton (he/him)
@Bradcomp
Dec 04 2016 23:31
Also has the type sig (Number, Number) -> Number
But with:
R.lensProp
Brad Compton (he/him)
@Bradcomp
Dec 04 2016 23:32
Well, I guess that still makes sens
sense
Johnny Hauser
@m59peacemaker
Dec 04 2016 23:32
Weren't we talking about the lens not lensProp?
Brad Compton (he/him)
@Bradcomp
Dec 04 2016 23:32
but then, the returned structure
Lens s a = Functor f => (a → f a) → s → f s
Yes!
Johnny Hauser
@m59peacemaker
Dec 04 2016 23:33
That one is curried, but you can't pass (a -> fa) and s at the same time, unlike everything else
Brad Compton (he/him)
@Bradcomp
Dec 04 2016 23:33
So the signature there doesn't accept the ((a → f a), s) → f s version
Johnny Hauser
@m59peacemaker
Dec 04 2016 23:34
Should I PR that and feel super cool?
Brad Compton (he/him)
@Bradcomp
Dec 04 2016 23:34
@ram-bot
uncurryN(3, lensProp)('foo', compose(Maybe.Just, R.inc), {foo: 1})
ram-bot
@ram-bot
Dec 04 2016 23:34
_Just { value: { foo: 2 } }
Brad Compton (he/him)
@Bradcomp
Dec 04 2016 23:35
@ram-bot
const ramdaCurryN = (n, f) => curry(uncurryN(n, f));
ramdaCurryN(3, lensProp)('foo', compose(Maybe.Just, R.inc))( {foo: 1})
ram-bot
@ram-bot
Dec 04 2016 23:35
_Just { value: { foo: 2 } }
Brad Compton (he/him)
@Bradcomp
Dec 04 2016 23:37
:-D
Johnny Hauser
@m59peacemaker
Dec 04 2016 23:37
lol
Brad Compton (he/him)
@Bradcomp
Dec 04 2016 23:39
It is interesting that lens doesn't return a ramda-curried function.
Johnny Hauser
@m59peacemaker
Dec 04 2016 23:40
am I reading this correctly? What I see is that it is curried with curry, but then manually currying by returning functions anyway
Brad Compton (he/him)
@Bradcomp
Dec 04 2016 23:41
IN the end, to get a value out, you need to pass in 4 parameters -> getter, setter, toFunctorFn, and target
it's ramda-curried WRT the first two parameters, but manually curried for the last two
Johnny Hauser
@m59peacemaker
Dec 04 2016 23:41
ah, right
should just ditch those and curry4
Johnny Hauser
@m59peacemaker
Dec 04 2016 23:48
Perhaps the goal was to avoid currying more than 3?
I'm not sure the rationale, but there are internal curry1, curry2, curry3, and they are complicated.
maybe some kind of performance boost
it says "optimized"
Johnny Hauser
@m59peacemaker
Dec 04 2016 23:54
So, perhaps it's a tradeoff there between inconsistent currying, performance, and extra code for adding _curry4.
and they decided on the former