To implement a visualized arithmetic expression editor in Haskell, I defined the following things:
data AST = Lit Int
| Add AST AST
| Neg AST
eval :: AST -> Int
type TagName = String
type Attrs = M.Map String String
data DOM = Tag TagName Attrs [SubDOM]
data SubDOM = SubNode DOM | Text String
toDOM :: AST -> DOM
fromDOM :: DOM -> AST
I want to make it possible for user to edit both the AST and the DOM, and sync the user operations (such as substitute a child node into another) between them, and further more, I want to sync operations efficiently (which means only the modified child node should be reconstructed), how should I approach this?
One solution is allocate each AST node and DOM node an id, and when an operation happens on one side, we sync this operation to the other side node with the same id, but this step seem tricky in functional programming, and I asked this question separatly: How to generate stable id for AST nodes in functional programming? .
Another solution is redefine the data structure, so that one side keep an IORef of the other side, and when an operation happens, we can sync the operation to the other side via the reference. But this approach seems not functional.
So, is there a best practice for this problem in functional programming?