These are chat archives for ramda/ramda

4th
Feb 2016
Jethro Larson
@jethrolarson
Feb 04 2016 04:15
Lensprop gives you assoc, prop, and evolve bundled together, plus easy composition
The benefit is negligible with shallow data or mutable structures.
For big imutable state objects they help quite a bit
Jack Firth
@jackfirth
Feb 04 2016 05:24
@dtipson I'd argue lenses in Ramda (and Haskell) do compose in reverse order
If you're just viewing, lenses are functions and composing them should behave like composing functions - `view(lensCompose(firstLens, secondLens), v)` should be equivalent to `compose(view(firstLens), view(secondLens))(v)`
The van Laarhoven representation of lenses is somewhat frustrating in this regard since it breaks this assumption
Scott Christopher
@scott-christopher
Feb 04 2016 05:50
The non-intuitive composition ordering affects the compositions of higher order functions in general.
e.g. consider the following:
``mapHead = f => R.converge(R.prepend, R.compose(f, R.head), R.tail));``
which just maps over the first value of a list
and
``mapNotNull = f => R.unless(R.isNil, f);``
which will transform a value unless it is `null`
``mapHeadNotNull = R.compose(mapHead, mapNotNull);``
will map over the first element of a list if it is not `null`
Scott Christopher
@scott-christopher
Feb 04 2016 05:58
``````mapNotNull     :: (a -> a) -> (a -> a)
mapHead        ::             (a -> a) -> ([a] -> [a])
mapHeadNotNull :: (a -> a)             -> ([a] -> [a])``````
``absHeadOrNull = mapHeadNotNull(R.abs) //:: [a] -> [a]``
Scott Christopher
@scott-christopher
Feb 04 2016 06:03
So while it is unintuitive, it's not just specific to lenses. It's the same for composing functions that take functions as arguments and return functions.
Jack Firth
@jackfirth
Feb 04 2016 06:14
@scott-christopher Lenses being higher-order functions is a bit of an implementation detail though - there's no need to keep it in mind when using an api providing lensCompose, view, set, over, etc.
Indeed, most newcomers to lenses have no idea they're functions until they learn about the details of the van Laarhoven representation
Scott Christopher
@scott-christopher
Feb 04 2016 06:56
It is just an implementation detail, but I was just highlighting why they compose the way they do. There's no reason why you can't create a `composeLens` function that does so in the intuitive order.
Tobias Pflug
@gilligan
Feb 04 2016 08:16
hi
Keith Alexander
@kwijibo
Feb 04 2016 08:17
hullo
@scott-christopher does `R.over` need a `lift` equivalent?
Scott Christopher
@scott-christopher
Feb 04 2016 08:20
Hi @gilligan
Tobias Pflug
@gilligan
Feb 04 2016 08:22
@scott-christopher just added some more comments to your profunctors PR
@scott-christopher hope they don't seem too negative
Scott Christopher
@scott-christopher
Feb 04 2016 08:24
@kwijibo Something like `mapped` should do what you need, if you're talking about applying a function to some functor as the focus of a lens (well, a traversal in this case)
@gilligan :thumbsup: I'm not sure I'll have time this evening to respond, but your questions are totally valid.
Keith Alexander
@kwijibo
Feb 04 2016 08:34
@scott-christopher I was thinking more, how would you do something like this with lenses:
``````const data = {  a: 42, b: 99 }
data.total = R.add(data.a, data.b)``````
Tobias Pflug
@gilligan
Feb 04 2016 08:34
@scott-christopher I am trying to at least try something in the repl but still pretty lost. Right now I am rather confused that no `view` implementation is declared
Tobias Pflug
@gilligan
Feb 04 2016 08:42
@scott-christopher oh, I think you forgot to add Getter.js to index.js
Martin Broder
@mrtnbroder
Feb 04 2016 09:00
Good morning everyone!
Tobias Pflug
@gilligan
Feb 04 2016 09:00
hi
Martin Broder
@mrtnbroder
Feb 04 2016 09:00
does someone have an idea on how to get rid of imperative switch statements?
in a more FP way?
Raine Virta
@raine
Feb 04 2016 09:00
try `R.cond`
Martin Broder
@mrtnbroder
Feb 04 2016 09:01
ah nice, thanks!
that was quick
lol
much better <3
Keith Alexander
@kwijibo
Feb 04 2016 09:03
:)
`cond` is like a `switch(true)` isn't it? I wonder if `R.switch([[val,transform]])` would be useful
(given at least 2 people have asked about `switch` in the last 24 hours)
Martin Broder
@mrtnbroder
Feb 04 2016 09:10
like an alias ?
makes sense to me.
another question now would be how to mimic switch statements 'fallthrough' behaviour
like
``````  return cond([
[equals(106), 'foo'],
[between(106, 108), 'i am wizard'],
])``````
is there something like that already?
I guess `R.anyPass`
Raine Virta
@raine
Feb 04 2016 09:21
sometimes I could use a variation of `cond` that did `equals` on the first value and `always` for the second:
``````cond([
[ equals('merge'), always(`\${mdBold('✓')} Merged by \${firstWord(payload.user.name)}, \${superb()}!`) ],
[ equals('close'), always(`\${mdBold('✗')} Closed by \${firstWord(payload.user.name)}`) ],
[ T,               always('') ]
])(action)``````
Martin Broder
@mrtnbroder
Feb 04 2016 09:24
is this the way to go btw?
``````return cond([
[equals(106), 'foobar'],
[anyPass([equals(107), equals(108)]), 'kazahm!']
])``````
Raine Virta
@raine
Feb 04 2016 09:24
no, as you can see from my example
second value in each inner list needs to be a function
Martin Broder
@mrtnbroder
Feb 04 2016 10:33
uhmmm
guys
``````R.is(Number, NaN)
true``````
...?
Keith Alexander
@kwijibo
Feb 04 2016 10:34
that's javascript for you
Martin Broder
@mrtnbroder
Feb 04 2016 10:35
javascript but it should be fixed in a lib like ramda :D
Keith Alexander
@kwijibo
Feb 04 2016 10:35
`typeof NaN // "number"`
yeah maybe
Martin Broder
@mrtnbroder
Feb 04 2016 10:36
I'll create an issue
Keith Alexander
@kwijibo
Feb 04 2016 10:36
bit hairy though, if you try to redefine js semantics?
actually Ramda already does: `R.is(Object, null)// false`
Martin Broder
@mrtnbroder
Feb 04 2016 10:38
yeah that's what I'd expect
Keith Alexander
@kwijibo
Feb 04 2016 10:38
it's not clear why though
if it's a "common-sense" interpretation of type comparisons, it should really be explained somewhere
I spose the docs say, it checks up the inheritance tree, and `null` doesn't have any `constructor` or `prototype` properties or anything
Keith Alexander
@kwijibo
Feb 04 2016 10:44
`null instanceof Object === false` but `typeof null === "object"`
Jakub Korzeniowski
@kujon
Feb 04 2016 10:50
I'd argue that the current implementation of `val != null && val.constructor === Ctor || val instanceof Ctor` is quite sensible. Both `null` and `undefined` represent no value. You'd expect to be able to call `Object.prototype` methods on `null` is it was truly an object as `typeof` suggests.
Keith Alexander
@kwijibo
Feb 04 2016 10:51
+1
Tobias Pflug
@gilligan
Feb 04 2016 11:07
@raine hm.. any idea what to call such a refined `cond` function ?
Keith Alexander
@kwijibo
Feb 04 2016 11:16
@gilligan @raine wouldn't that be `R.prop(R.__)` ?
(if you provide the key value mappings as an Object-as-dictionary)
fwiw, I often do `const lookup = R.prop(R.__)`, it would be kinda nice if there was a `R.lookup`
Raine Virta
@raine
Feb 04 2016 11:22
there used to be `R.propOf` or something
kwijibo @kwijibo likes @gilligan's pictographs at the bottom of ramda/ramda-lens#2
Keith Alexander
@kwijibo
Feb 04 2016 12:18
@mrtnbroder should R.is always return false if 2nd argument is NaN ?
Tobias Pflug
@gilligan
Feb 04 2016 12:37
@scott-christopher still around?
Drew
@dtipson
Feb 04 2016 14:59
@jackfirth I'd still argue that "they" aren't composing in reverse order. Composition is still running right to left, it's just that what's running through the composition isn't a steadily mutated value, but a wrappable function. When you run the result, the operations listed may run left to right, but that's sensibly because the leftmost thing added is the last and thus the outermost layer
Jack Firth
@jackfirth
Feb 04 2016 21:37
@dtipson What does "outermost" mean? The lens that views the input first? What's to stop the argument that the function that gets the input first in a composed function chain is the "outermost" function and the function last in the chain is "innermost"? These are informal concepts. I'm a much bigger fan of formalizing the intuition that "well if I don't set, lenses are just getter functions and compose like getter functions" since that's what users expect.
Scott Christopher
@scott-christopher
Feb 04 2016 21:48
Except lenses aren't getter functions, `view(lens)` is a getter function which composes the way you'd expect.
@gilligan I'm around now if you still are :)
Jack Firth
@jackfirth
Feb 04 2016 21:56
@scott-christopher They're not, but they're extremely related to them and that's how many users think of them, as composable functional getter-setter pairs. Lensesrepresent a bidirectional computation. If functions in general represent unidirectional computation, than it makes sense why people find the current order "weird" - they assume if you're not using the "go back" part (set/over) it doesn't matter whether a computation is expressed using bidirectional components or unidirectional components. But because the order is different between those two cases, that assumption is broken.
Half the decent lens tutorials begin with "hey, here's deeply nested data. here's getting the deeply nested part by composing getters. here's getting the deeply nested part by composing lenses. whoa the composed lens lets you set it too, isn't that cool?!?!"
"lenses represent", *then, probably other errors in various places (I'm tired)
Keith Alexander
@kwijibo
Feb 04 2016 22:02
if we say "composes in reverse order" can't apply to transducers or lenses, are we not pretending we don't understand what is meant? of course everything composes just the same with the same `compose` function; what's meant is the sequence of data-traversal goes L->R, while the sequence of composition goes R->L
Scott Christopher
@scott-christopher
Feb 04 2016 22:02
I completely agree that composition of van Laarhoven style lenses is counterintuitive at first glance. It is a bit of a curse for the sake of intuition that they compose rather elegantly with plain ol' function composition, but I'm glad they do.
Jack Firth
@jackfirth
Feb 04 2016 22:07
I'm not. In Haskell it circumvents the type system and makes error messages very complex. The main problem with having individual operators for lens composition, getter composition, iso composition, etc. in Haskell is the "type tower" they create - composing a Lens with a Prism automatically produces a Traversal, for example. I question whether `someTraversal = someLens . somePrism` is better than `someTraversal = traversalCompose (lensToTraversal someLens) (prismToTraversal someTraversal)`. The first looks nicer, but if you mess things up the type errors will be completely unhelpful.
Not to mention it's difficult for those new to lenses to decipher
Tobias Pflug
@gilligan
Feb 04 2016 22:20
@scott-christopher ;-)
Tobias Pflug
@gilligan
Feb 04 2016 22:26
@scott-christopher like I said in the PR discussion, if those wip examples were online somewhere that'd be cool. Don't even mind the state they are in. Could just really need some usage examples to figure out some things. Have you seen the docs i am trying to write?
Scott Christopher
@scott-christopher
Feb 04 2016 22:29
@gilligan I haven't had a chance to look yet, but I'll find some time later today.
Scott Christopher
@scott-christopher
Feb 04 2016 22:52
@gilligan Looks like a great start. I'd be happy to help fill in the blanks.
I think we would benefit a lot by explaining the different type aliases in use and how they relate to each other.
I also want to get together a "Profunctors in Pictures" explanation, which I think would help towards understanding some of the implementation.
Tobias Pflug
@gilligan
Feb 04 2016 23:18
@scott-christopher have to get some sleep now. I will just bug you with some more questions on github then. Like right now lens_ is already confusing me. Hence my desire for some examples so I can better deduce some things. Other than that I will have to read up on Strong
and Choice