-
Notifications
You must be signed in to change notification settings - Fork 30
Description
I have the following type definitions in F#. How can I create a lens from Parent to a given GrandChild (identifier by ID)?
type GrandChild = { Id: int }
type Child = { Id: ChildId; Children: GrandChild list }
type Parent = { Children: Map<ChildId, Child> }Here is my ugly attempt, which seems like just the kind of thing lenses is used to avoid:
module Parent =
let grandChild grandChildId : Lens<Parent, GrandChild> =
(fun x ->
x.Children
|> Map.toList
|> List.collect (fun (_, c) -> c.GrandChildren)
|> List.find (fun gc -> gc.Id = grandChildId)
),
(fun v x ->
{
x with
Children =
x.Children
|> Map.map (fun _ c ->
{ c with
GrandChildren =
c.GrandChildren
|> List.map (fun gc -> if gc.Id = grandChildId then v else gc) }
)
}
)I'm not even sure this follows the optic laws.
Part of my challenge here is that there is no correspondence between the child IDs and the grandchild IDs. When I'm at the parent level and want to update a specific GrandChild, I have to check all Children and all GrandChildren.
I assume that there is an easier and more composable way of doing this, but it's escaping me.
If it would simplify anything, you can assume that the grandchild specified by grandChildId is guaranteed to exist in the hierarchy (hence the use of Lens instead of Prism).