How to fold over a discriminated union

蓝咒 提交于 2019-12-06 12:27:39

The first question is, what kind of fold do you want to implement? There is a number of options for tree-like structures. Assuming you have an n-ary tree (that is, any number of children), you can:

  1. Apply the folding function only on Expr nodes in the leafs
  2. Apply the folding function on the leafs and then apply it to all internal nodes (after a recursive call)
  3. Apply the folding function on the internal nodes while processing the tree and then on leafs

In your example, your folder function takes Expr list which is a bit confusing to me - I would think you could just give it the current Expr and not a list of children, but calling it on children is an option too.

You're first making a recursive call and then calling the folder on current expression, so I suppose you wanted to implement the option 2. I can understand the first two lines of your folding:

// This defines a function that recursively folds the a given 
// expression and produces a new state of type 's
let listFolder = fun state expr -> foldProceduralExpr folder state expr 
// Here, you fold all children recursively starting with 'state' and 
// obtaining a result 'listFolded' of type 's
let listFolded = List.fold listFolder state children 

However, the last line is probably wrong:

// From the previous line, 'listFolded' is of type 's, but 
// here you use it as if it was a list:
folder state (expr :: listFolded) 

I assume you probably want to use listFolded as the state passed to the folder. The folder takes a list of expressions, so you can give it children as the second argument (or you can change folder to take just a single Expr and then give it just expr, which would IMHO make more sense). Anyway, this should make it work, so that you can run it and see what is going on:

folder listFolded children

I wrote an article once about a practical approach to maintaining code involving large discriminated unions and their transforms:

http://t0yv0.blogspot.com/2011/09/transforming-large-unions-in-f.html

In practice I find that fold assumes too much, there are frequently transformations that cannot be expressed in terms of fold. You also want control over how the transformation is going - bottom-up or top-down, and which nodes are skipped or handled specially. The article shows how to do this in terms of a simple transform function. I also derive a fold in just a few lines from transform.

It does not directly answer how to fix your problem, but it might shed some light on another way to structure such code.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!