In Lua, I have a tree relationship structure between objects where an object can have multiple children, but only one parent object, i.e.
obj---obj1---obj2---objd3---obj4---obj5---obj6
If I want to know obj6's 'distant' parents instead of just the immediate parent obj5, how can I achieve that? I just need a list of parents two or more levels above the current object, and the API I'm working with only has a obj.parent property.
Pseudo-code would also be helpful to get me in the right direction.
obj.parent -- immediate parent (obj5)
obj.parent.parent -- parent's parent (obj4)
obj.parent.parent.parent -- parent's parent's parent (obj3)
So on and so forth?
If you want to avoid trying to referencing a non-existent parent, I supposed you could do something like:
function getAncestor(obj, depth)
if not obj.parent then
return nil
elseif depth > 1 then
return getAncestor(obj.parent, depth-1)
end
return obj.parent
end
-- get parent
obj = getAncestor(obj6)
-- get great great grandparent
obj = getAncestor(obj6, 3)
Well, if your api supports .parent, can't you do something like the following? I'm rusty with Lua but this should offer a start.
local function GetAncestors(child)
local ancestors = {};
if child.parent then
local i = 0;
ancestors[0] = child.parent;
while ancestors[i].parent do
ancestors[i + 1] = ancestors[i].parent;
i = i + 1;
end
end
return ancestors;
end
Related
Assume u have the following recursive record type
type Parent = {
Name : string
Age : int
Children : Child list }
and Child = {
Name : string
Parent : Parent option }
I can easily create instances with
module Builder =
let create name kids =
let rec makeChild kid = { kid with Parent = parent |> Some }
and parent =
{
Name = name
Age = 42
Children = children
}
and children = kids |> List.map makeChild
parent
let createChild name =
{ Child.Name = name; Parent = None }
But when i try to "transform" an existing adult into a parent using "with" like that:
module Builder2 =
let createAdult name age =
{ Parent.Name = name; Age = age; Children = [] }
let create name kids =
let rec makeChild kid = { kid with Parent = parent |> Some }
and parent =
{ (createAdult name 42) with
Children = children
}
and children = kids |> List.map makeChild
parent
let createChild name =
{ Child.Name = name; Parent = None }
I get:
error FS0040: This and other recursive references to the object(s) being defined will be checked for initialization-soundness at runtime through the use of a delayed reference. This is because you are defining one or more recursive objects, rather than recursive functions. This warning may be suppressed by using '#nowarn "40"' or '--nowarn:40'.
and "Children = children" in the "parent" definition is highlighted.
What am i doing wrong?
Edit:
One more point: when i move the "Builder" (which worked) into a different assembly (e.g. the test assembly) it immediately stops working with:
error FS0261: Recursive values cannot be directly assigned to the non-mutable field 'Children' of the type 'Parent' within a recursive binding. Consider using a mutable field instead.
Edit:
Based on the comments I tried
let create name kids =
let rec makeChild kid = { kid with Parent = parent |> Some }
and adult = createAdult name 42
and parent =
{ adult with Children = children }
and children = kids |> List.map makeChild
but still no luck - the compiler still does not see this usecase similar to the working one :(
First of all, the message you posted in your question is just a warning - it tells you that you can only initialize a recursive value if the construction does not evaluate the entire value immediately (this cannot be done when the first value depends on the second and vice versa).
You can sometimes just ignore the warning, but in your case, the values are actually mutually dependent, so the following gives an error:
Builder2.create "A" [Builder2.createChild "B"]
System.InvalidOperationException: ValueFactory attempted to access the Value property of this instance.
One way to introduce some form of delay is to change the parent to include children as a lazy sequence seq<'T> rather than a fully evaluated list list<'T>:
type Parent = {
Name : string
Age : int
Children : Child seq }
and Child = {
Name : string
Parent : Parent option }
Then you also need to change Builder2 to use Seq.map (to keep things lazy):
let create name kids =
let rec makeChild kid = { kid with Parent = parent |> Some }
and parent =
{ (createAdult name 42) with
Children = children
}
and children = kids |> Seq.map makeChild
Now you still get the warning (which you can turn off), but the following works and creates a recursive value:
let p = Builder2.create "A" [Builder2.createChild "B"]
As an aside, I think it is probably better to avoid recursive values - I suspect that one way reference (parent referencing children, but not the other way round) would let you do what you need - and your code would likely be simpler.
cartermp found and posted the solution here:
https://github.com/Microsoft/visualfsharp/issues/4201
I published a repro here
https://github.com/plainionist/DevNull/tree/master/src/FSharpCopyRecordRecursive
and of course the proposed solution works like a charm
Suppose I have a global dict parent that contains some child like
parent = Dict( child1, child2, ...);
And each child is another dict of
child = Dict("weight" => 100.0; "height" = 10.0);
Is there a way to sort these childs in the parent respect to some category? Like I want to product a parent which has the child nodes sorted according to their weight?
Thanks,
So,
sort!(parent,by=x->x["weight"])
should do the trick. Use sort (no !) to return a new vector. Try ?sort in REPL for more options.
I'm trying to do a cyclic graph in F#
My node type looks something like this:
type Node = { Value : int; Edges : Node list }
My question is: Do I need to make Edges mutable in order to have cycles?
F# makes it possible to create immediate recursive object references with cycles, but this really only works on (fairly simple) records. So, if you try this on your definition it won't work:
let rec loop =
{ Value = 0;
Edges = [loop] }
However, you can still avoid mutation - one reasonable alternative is to use lazy values:
type Node = { Value : int; Edges : Lazy<Node list>}
This way, you are giving the compiler "enough time" to create a loop value before it needs to evaluate the edges (and access the loop value again):
let rec loop =
{ Value = 0;
Edges = lazy [loop] }
In practice, you'll probably want to call some functions to create the edges, but that should work too. You should be able to write e.g. Edges = lazy (someFancyFunction loop).
Alternatively, you could also use seq<Edges> (as sequences are lazy by default), but that would re-evaluate the edges every time, so you probably don't want to do that.
This is a somewhat beginner question. I have been trying to validate the following type of FamilyTree. I can't find a simple way to do this. All help would be appreciated.
type BirthYear = int;;
type Tree = Person of BirthYear * Children
and Children = Tree list;;
I want to validate a given family tree such that every Person is older than their Children and furthermore check if the list of Children is sorted in order of their age (eldest first). Preferably done with a function that return a boolean. Something along the lines of this:
let rec validate (Person(x,child)) =
let vali = child |> List.forall (fun (y,_) -> y < x)
I'd do something like this:
let rec checkAges minBirth = function
| Person(b, _) :: t -> b >= minBirth && checkAges b t
| [] -> true
let rec validate (Person(b, c)) =
List.forall validate c && checkAges (b + minParentAge) c
where minParentAge is set to a reasonable minimum age to have children at.
I'd expect checkAges to be the more difficult part here: the function checks whether the first child it sees is younger than the limit it is given, then recursively checks the next child, with the current child's age as the new limit.
Note some techniques:
The function that checks child ages takes the minimum birthday as input; this is used to validate that the parent is old enough for the first child to be reasonable.
List.forall checks a predicate for all items in a list, and early-outs if a predicate is not fulfilled
function is a shorthand to create a function that does pattern matching on its parameter. Therefore, checkAges actually has two arguments.
Here's a very simple solution using a single recursive function. It's not relying on built-in functions like List.forall but I think it's very declarative and (hopefully) easy to follow.
Rule 1: Every Person is older than their Children
Rule 2: List of Children is sorted in order of their age (eldest first)
Code:
let rec isValid = function
| Person ( _ , []) -> true // Person alone without childs -> always valid
| Person (minYear, Person (year, childs) :: brothers) ->
year > minYear && // Validate Rules (either 1 or 2)
isValid (Person (year, childs)) && // Enforce Rule 1
isValid (Person (year, brothers)) // Enforce Rule 2
I personally don't feel List.forall fits well here, it helps to solve a part of the problem but not the whole, so you need to combine it with more stuff (see the other answers) and in the end you can't avoid a recursive function.
List functions are good for lists but for trees I feel recursion more natural unless your tree provides already a way to traverse it.
Here's a way to do it. Perhaps spending some time analyzing how this works will be helpful to you.
let rec check (Person(age, children)) =
match children with
| [] -> true
| Person(eldest, _)::_ ->
Seq.pairwise children |> Seq.forall ((<||) (>))
&& age > eldest
&& List.forall check children
I wonder if this is even possible at all as the question suggest.
My problem is that I cannot seem to grasp how to handle the fact that a given input value can have multiple children. The problem is easily solved by using the mutable SortedSet variable as shown below. But I would really like to find out if this is a problem possible to solve with pure recursion and creation of new un-muted lists or similar. I hope my question is clear. I fear I'm ignorant to the easy conclusion that it's not possible.
As you can see bellow the if(true) will return a list but the else will return a list of list. So the code bellow is not in working state.
let someSet = new System.Collections.Generic.SortedSet<string>()
let rec children(value:string,listSoFar) =
printfn "ID: %A" value
someSet.Add(value) works fine of course.
let newList = List.append listSoFar [value]
if(not (hasChildren(value))) then
newList
else
let tmpCollection = database.GetCollection<Collection>("Collection")
let tmpQuery = Query.EQ("Field",BsonValue.Create(value))
let tmpRes = tmpCollection.Find(tmpQuery)
[ for child in tmpRes do
yield children(child.Value,newList) ]
let resultList = children("aParentStartValue",[])
//Or do i need to use someSet values?
Unless the tree is very deeply nested (in which case, this would be inefficient), you can write the code as a recursive F# sequence expression that generates elements using yield and yield!
let rec children (value:string) = seq {
// Produce the current value as the next element of the sequence
yield value
if hasChildren value then
// If it has children, then get all the children
let tmpCollection = database.GetCollection<Collection>("Collection")
let tmpQuery = Query.EQ("Field",BsonValue.Create(value))
let tmpRes = tmpCollection.Find(tmpQuery)
// For each child, generate all its sub-children recursively
// and return all such elements as part of this sequence using 'yield!'
for child in tmpRes do
yield! children child.Value }
// Using 'List.ofSeq' to fully evaluate the lazy sequence
let resultList = List.ofSeq (children "aParentStartValue")
If the tree is more deeply nested, then the situation is a bit more difficult. When iterating over all the children, you'd need to pass the list collected so far to the first children, get the results and then pass the resulting list to the next children (using something like List.fold). But the above is clean and should work in most cases.