I just learned about lift and applicatives and on my quest to trying to understand these structures I am trying to implement a real use case.
I have a List (array) that is lazy, meaning that I can't get the count of items or their children until I load it. getting the nodes and loading it is async, same for its nested children (if any).
so if I would have the structure below:
[{title:"test1",children:[]},{title:"test2",children:[{title:"test2_1",children:[]}]}]
For each one of the children I don't know if they have children until I load the node and check the children count.
How could I check the entire list with FP (regardless of how nested it can go) either:
-By loading and checking each node at the time. and stop when we find a match or run out of nodes.
or
-By loading all nodes then (probably nesting it into Rights() and Lefts()), flattening into a single list, then foldmapping for a item by title with a predicate just like in the example below.
This is what I know works for the first match of a element in a non nested array:
[{title:"test1"},{title:"test2"},{title:"test3"}] //structure we are loading
const find= (l,f)=>l.foldMap(x=>First(f(x)?Right(x):Left()),First.empty())
const nodes = await getNodes() //not gonna even put in a type just to illustrate that getting and loading the nodes is async.
const list = List(await load(nodes)) //not gonna even put in a type just to illustrate that getting and loading the nodes is async.
console.log(find(list,x=>x.title==='test3').fold(x=>x).fold(console.error,x=>x))
Edit: current imperative working code:
This is a sharepoint code that will get all nested navigation nodes from the globalNav. The important thing is I want to understand how I can turn this into a FP implementation preferable using applicatives.
GetNavigationNodeChildren = node => node.get_children();
GetNavigationNodeRoot = spCtx => spCtx.get_web()
.get_navigation().get_topNavigationBar();
ExecQuery = spCtx => resource => {
return new Promise((res, rej) => spCtx.executeQueryAsync(
() => res(resource),
(s, a) => rej({ s, a }),
));
};
LoadResource = spCtx => resource => (spCtx.load(resource) ? resource : resource);
LoadAndExec = spCtx => async resource => {
LoadResource(spCtx)(resource )
await ExecQuery(spCtx)(resource )
return resource
}
getAll = spCtx=> async resource=> {
return {node:await LoadAndExec(spCtx)(resource),children:await hasChildren(c)(resource.get_children())}
}
hasChildren = spCtx => async resource => {
LoadResource(spCtx)(resource )
await ExecQuery(spCtx)(resource )
return Promise.all(resource.get_count()>0?resource.get_objectData().$1G_0.map(await getAll(spCtx)):[])
}
c=new SP.ClientContext()
root=GetNavigationNodeRoot(c)
await LoadAndExec(c)(root)
all=await hasChildren(c)(root)
PS: Look... The idea is to learn and understand FP, please if all you have to say is that I don't need to change the code/I am making it complicated... That is really not the point of the question.