These are chat archives for ramda/ramda

9th
Oct 2016
Scott Christopher
@scott-christopher
Oct 09 2016 00:15
@jigargosar I don't know how practical this will be (or whether it would even work :D) but if you can modify the shape of the data structure to be traversable then you could make use of something like traversed from the ramda-lens library to target all of nodes and then compose that with a lens that targets the title of each note but the setter will effectively be identity if the given id doesn't match.
So if you have a Tree structure like:
class Tree {
  constructor(payload, children) {
    this.payload = payload;
    this.children = children;
  }
  map(f) {
    return new Tree(f(this.payload), this.children.map(t => t.map(f)));
  }
  sequence(of) {
    return this.traverse(of, x => x);
  }
  traverse(of, f) {
    return f(this.payload)
      .map(newPayload => newChildren => new Tree(newPayload, newChildren))
      .ap(R.traverse(of, t => t.traverse(of, f), this.children));
  }
}
You could create a Note constructor such as:
const Note = (id, title, notes) =>
  new Tree({ id, title }, notes);
So if your hierarchy of notes looks something like:
const notes = [
  Note(1, '', [
    Note(2, '', []),
    Note(3, '', [])
  ]),
  Note(4, '', [
    Note(5, '', []),
    Note(6, 'view this note', [])
  ])
];
You could target note with ID 6 like:
const titleOfId = n => R.lens(
  x => x.title,
  (title, payload) => payload.id === n ? R.assoc('title', title, payload) : payload
);

over(compose(traversed, traversed, titleOfId(6)), R.toUpper, notes)
Denis Stoyanov
@xgrommx
Oct 09 2016 00:19
@scott-christopher also we can use es6 generators =) https://jsbin.com/dehetas/3/edit?html,js,output
Scott Christopher
@scott-christopher
Oct 09 2016 03:20
@jigargosar Another approach similar to the one you've taken could involve creating a lens that searches for the node, building up a setter function as it goes.
This message was deleted
ram-bot
@ram-bot
Oct 09 2016 03:20
Unexpected token [
Scott Christopher
@scott-christopher
Oct 09 2016 03:21
@ram-bot
const indexedChain = R.addIndex(R.chain);

// Find a note with the given `id`, building up a "setter"
// that is returned along with the found value.
const findWithSetter = (id, notes) => {
  const go = (setter, id, notes) =>
    indexedChain((n, idx) =>
        n.id === id
          ? [setter(R.update(idx)), n]
          : go(f => setter((a, s) => R.update(idx, R.assoc('notes', f(a, s[idx].notes), s[idx]), s)), id, n.notes),
      notes
    );
  return go(f => (a, s) => f(a, s), id, notes);
};

// Constructs a lens that focuses on the potentially nested
// note with an ID matching that of the given value.
const findIdL = id => (toF => notes => {
  const setterAndValue = findWithSetter(id, notes);
  const setter = setterAndValue[0];
  const value = setterAndValue[1];
  return toF(value).map(newVal => setter(newVal, notes));
});

const notes = [{
  id:1, notes:[{
    id:2, notes:[]
  }, {
    id:3, notes:[]
  }]
}, {
  id: 4, notes: [{
    id: 5, notes: [{
      id: 6, title: "view this note", notes: []
    }]
  }]
}];

over(compose(findIdL(6), lensProp('title')), R.toUpper, notes);
ram-bot
@ram-bot
Oct 09 2016 03:21
[ { id: 1, notes: [ { id: 2, notes: [] }, { id: 3, notes: [] } ] },
  { id: 4,
    notes: 
     [ { id: 5,
         notes: [ { id: 6, title: 'VIEW THIS NOTE', notes: [] } ] } ] } ]
Scott Christopher
@scott-christopher
Oct 09 2016 03:22
The code is however pretty dense and unfriendly.
Jigar Gosar
@jigargosar
Oct 09 2016 08:02
@scott-christopher thanks a tones. Just getting to study about how you approach a problem and come up with solutions, is simply amazing. I am deeply grateful. Traversable is another concept that I have been struggling to understand. I will deeply study all the code. This knowledge should have been universally available and popular. But alas, after 15 years of imperative programming I am discovering it. I would love to contribute in spreading this knowledge. For now I am saving all these examples, for future blog posts , credited to you ofcourse :)
Jigar Gosar
@jigargosar
Oct 09 2016 08:24

@scott-christopher the first traversable solution requires one to know how deep the element is, right? (we had to use traversed twice in compose.). If so, it doesn't address my current problem. But I like the the way code is organized. Will pick that up.

In your second solution, we are building lens as we go, instead of doing it in the end, (as done in my solution). I think both solutions are pretty dense :) That's why I attempted traversing a tree with kidsLens separate from creating the lens itself. Can you share pros and cons of both our approaches? It will help me assimilate this knowledge. And thanks again.

@xgrommx I will try to implement this solution using generator, and share it here. Thanks for pointing out :D
Scott Christopher
@scott-christopher
Oct 09 2016 08:27
The reason there were two traversed composed together in the first example is because the first traversable structure was a list, and the second was the trees within the top list. The tree itself will get traversed as a whole.
Jigar Gosar
@jigargosar
Oct 09 2016 08:48
@scott-christopher ooh, thanks for that. Will take a look again. I don't mind changing data structure if it makes things easier.
Scott Christopher
@scott-christopher
Oct 09 2016 08:48
As for building the lens in the second example, you only really build the lens once (e.g. when findIdL(6) is called), but it only builds the "setter" part on demand once it knows the path to the the node with the matching ID. You could split these out into a distinct getter and setter, constructing the lens with R.lens, though you'd end up traversing the structure twice when using over/set by first having to find the node to get the value and again to find the node to update the value. That could be a sane tradeoff for a potential boost in readability.
Jigar Gosar
@jigargosar
Oct 09 2016 08:50
@scott-christopher fair enough. thanks for explaining that. Your solution is very optimal. I think I get it now :)
Scott Christopher
@scott-christopher
Oct 09 2016 08:53
and it's worth keeping in mind that if you only need either a getter or a setter, without any notion of composition, then you might be better off skipping the use of lenses and just construct the getter/setter directly.
it's easy to get carried away with seeing what's possible to implement with lenses while losing sight of a potentially simpler solution :D
Jigar Gosar
@jigargosar
Oct 09 2016 08:56
@scott-christopher touché.
in my example I am storing the id of currently selected note, so I need to fetch it when rendering the note body/title editor
also I need to traverse the graph, with previous and next elements, when arrow keys are pressed.
traversable should help with that right? finding next/prev notes. As in your first solution.
Scott Christopher
@scott-christopher
Oct 09 2016 09:06
Traversable is all about visiting each item in a structure and performing some applicative action/effect.
For example, we could visit each node in a tree, producing some Maybe value at each node, then if every node returns a Just we will end up with the whole tree inside a Just. If any one node produces a Nothing, the whole traverse will evaluate to Nothing.
Jigar Gosar
@jigargosar
Oct 09 2016 09:08
ok, there is javascript tutorial documentation of "Kmett-style lenses", will I have to learn haskell for that?
still trying to get a hang of applicatives, (pointed functors). even though I have read "mostly adequate guide" :(
Scott Christopher
@scott-christopher
Oct 09 2016 09:11
@ram-bot
class Tree {
  constructor(payload, children) {
    this.payload = payload;
    this.children = children;
  }
  map(f) {
    return new Tree(f(this.payload), this.children.map(t => t.map(f)));
  }
  sequence(of) {
    return this.traverse(of, x => x);
  }
  traverse(of, f) {
    return f(this.payload)
      .map(newPayload => newChildren => new Tree(newPayload, newChildren))
      .ap(R.traverse(of, t => t.traverse(of, f), this.children));
  }
}

const t = new Tree(1, [
  new Tree(2, [
    new Tree(3, []),
    new Tree(4, [])
  ]),
  new Tree(5, []),
  new Tree(6, [])
]);

t.traverse(
  Maybe.of,
  n => n < 10 ? Maybe.Just(n) : Maybe.Nothing()
)
ram-bot
@ram-bot
Oct 09 2016 09:11
Block-scoped declarations (let, const, function, class) not yet supported outside strict mode
Scott Christopher
@scott-christopher
Oct 09 2016 09:12
Guess @ram-bot doesn't like class syntax yet.
I don't think I know of any JS tutorials on lenses. I could walk you through how they're implemented in Ramda if you're curious.
Jigar Gosar
@jigargosar
Oct 09 2016 09:17
@scott-christopher thanks for the repl link, I will study it in detail, and also the traverse function. This can serve as a good example in ramda documentation of traverse. :)
reagrding lenses, I was talking about the ramda-lens library, which links to http://lens.github.io/
primarily I was referring on how to use that library, with examples. Do you think going through its js implementation will help?
Scott Christopher
@scott-christopher
Oct 09 2016 09:20
the lens functions in both ramda and the ramda-lens library implement the van Laarhoven style lenses that are probably most famous from Kmett's lens library
Jigar Gosar
@jigargosar
Oct 09 2016 09:22
js world needs tutorials/examples/usage badly :(
quite easy to understand paper about Laarhoven lenses. Not too-deep but ok
@jigargosar We need more ramda advocates :-) And seniors using it in production and training juniors to use ramda and fp and all the good stuff...
Btw, I think its really necessary to be able to read a bit of haskell if you really want to study FP. Most papers use Haskell and in order to grasp them its quite important to be able to reproduce the stuff in there… So I am studying it , even thouhg I have a really hard time with it...
Jigar Gosar
@jigargosar
Oct 09 2016 09:55
@MarkusPfundstein me too I have started learning haskell. But it is a slow process. thanks for the link.
Markus Pfundstein
@MarkusPfundstein
Oct 09 2016 09:58
biggest problem is that I can’t find a cool side project for Haskell :D if I want to get stuff done I choose js
Jigar Gosar
@jigargosar
Oct 09 2016 09:58
@MarkusPfundstein went through the paper, I already understand, (set, over, and view). ramda-lens have some more stuff in it, (iso, folds, traversable...) Although the source is pretty small. The concepts and their application, is where I need examples.
Markus Pfundstein
@MarkusPfundstein
Oct 09 2016 09:59
i think the best way to learn is to implement for yourself
I implemented all kind of Monads in flow-type
now I understand them mostly and can also follow the code in ramda-fantasy for instance
Jigar Gosar
@jigargosar
Oct 09 2016 09:59
ya my side project is also in js. And since we don't code Haskell everyday, it takes longer.
@MarkusPfundstein that is a great advice. thanks.
Markus Pfundstein
@MarkusPfundstein
Oct 09 2016 09:59
so implement traverse by yourself , implement a lens..
Jigar Gosar
@jigargosar
Oct 09 2016 10:00
yup, that paper should help me with implementation. :)
Markus Pfundstein
@MarkusPfundstein
Oct 09 2016 10:01
my first exercise was to implement https://cse.sc.edu/~mgv/csce330f16/wadler_monadsForFP_95.pdf in JS
its the basic paper for Monads AFAIK. thus a very good and basic introduction without any of the complexities that people have invented in the last 20 years :P
Jigar Gosar
@jigargosar
Oct 09 2016 10:01
let me try this experiment, learning FP by writing your own implementations of all the high level concepts.
Markus Pfundstein
@MarkusPfundstein
Oct 09 2016 10:02
cool, let me know how you are doing. maybe can form a study group or so
i am quite at the bascis as well...
Jigar Gosar
@jigargosar
Oct 09 2016 10:02
sure
all the FP concepts are not difficult to understand from implementation point of view, for e.g. if you have read. https://github.com/fantasyland/fantasy-land then there is no reason to fear any FP jargon.
Markus Pfundstein
@MarkusPfundstein
Oct 09 2016 10:03
one more tip if I may: use typescript or flow. It helps tremendously if you have types.. Otherwise you eventually do and learn stuff that is not allowed
Jigar Gosar
@jigargosar
Oct 09 2016 10:04
monad, just an obj with bunch of functions. It is the usage, advantage, example, those are hard to grasp.
Markus Pfundstein
@MarkusPfundstein
Oct 09 2016 10:04
FL is awesome , this and Dr. Boolean
anda bunch of laws
:P
Jigar Gosar
@jigargosar
Oct 09 2016 10:04
yup, same boat then
I tried using types, but gave up quick, too much complexity. But for a study project, it is a good advise. Also, TS/Flow types are not strict, like those in SanctuaryJS.
but it will still help IMHO.
Markus Pfundstein
@MarkusPfundstein
Oct 09 2016 10:06
flow has quite good types. but yeah its tedious in the beginning
Jigar Gosar
@jigargosar
Oct 09 2016 10:08
does it support type classes?
Markus Pfundstein
@MarkusPfundstein
Oct 09 2016 10:09
flow has quite good types. but yeah its tedious in the beginning
but for studying,
it REALLY helps
i mostly had the idea that when it compiles: it works
Jigar Gosar
@jigargosar
Oct 09 2016 10:10
:)