Go转F#:如何实现可互相调用的函数字典?
解决F#中递归函数字典的引用问题
嗨,这个问题我之前也碰到过,F#的顺序敏感绑定确实容易在这里卡壳,不过有两种很实用的解决方案,我给你一步步讲清楚~
核心问题所在
你原来的代码里,processC在funcMap之前定义,而F#的顶级绑定是按顺序执行的——当编译器处理processC时,funcMap还没被创建,自然没法引用。而且你的场景里函数和字典互相依赖(部分函数要调用字典里的其他函数),这就需要用递归绑定或者参数传递的方式来打破这个顺序限制。
方案一:用let rec ... and ...创建递归绑定
F#允许用let rec配合and关键字,把一组互相依赖的绑定(函数、映射等)放在一起定义,编译器会自动处理它们的依赖关系。修改后的代码如下:
let rec processA a remainingCharacters = 1 and processB b remainingCharacters = 2 and processC c remainingCharacters = // 现在可以正常引用funcMap了! let nextChar = remainingCharacters.Head let nextFunc = funcMap |> Map.find nextChar // 这里修正了你原代码里未定义的`problem`变量,假设是调用下一个函数并累加值 nextFunc nextChar remainingCharacters.Tail + 3 and funcMap = Map [('a', processA); ('b', processB); ('c', processC)] let processCharacter currentCharacter remainingCharacters = let processFunc = funcMap |> Map.find currentCharacter processFunc currentCharacter remainingCharacters let input = ['a'; 'b'; 'a'; 'c'] let processInput() = let rec processInputRec currentCharacter (remainingCharacters: char list) sum = if remainingCharacters.IsEmpty then sum else let currentValue = processCharacter currentCharacter remainingCharacters processInputRec remainingCharacters.Head remainingCharacters.Tail (sum + currentValue) processInputRec input.Head input.Tail 0 let result = processInput() printfn "%i" result
这个方案的好处是代码简洁,保持了函数的原有签名,不需要额外传参。
方案二:将函数字典作为参数传递给处理函数
如果你觉得递归绑定有点“魔法”,也可以选择更直白的方式:把funcMap作为参数传给每个处理函数,这样函数就不需要提前引用还没定义的字典了。示例代码:
// 每个处理函数都多接收一个funcMap参数 let processA funcMap a remainingCharacters = 1 let processB funcMap b remainingCharacters = 2 let processC funcMap c remainingCharacters = let nextChar = remainingCharacters.Head let nextFunc = funcMap |> Map.find nextChar // 调用下一个函数时也要把funcMap传进去 nextFunc funcMap nextChar remainingCharacters.Tail + 3 // 定义字典时,每个值都是接收funcMap的函数 let funcMap = Map [ ('a', processA) ('b', processB) ('c', processC) ] // 调用时需要把funcMap传递给处理函数 let processCharacter currentCharacter remainingCharacters = let processFunc = funcMap |> Map.find currentCharacter processFunc funcMap currentCharacter remainingCharacters // 后面的input和processInput逻辑和你原来的一致 let input = ['a'; 'b'; 'a'; 'c'] let processInput() = let rec processInputRec currentCharacter (remainingCharacters: char list) sum = if remainingCharacters.IsEmpty then sum else let currentValue = processCharacter currentCharacter remainingCharacters processInputRec remainingCharacters.Head remainingCharacters.Tail (sum + currentValue) processInputRec input.Head input.Tail 0 let result = processInput() printfn "%i" result
这种方式的优点是逻辑更直观,函数的依赖关系一目了然,而且如果以后需要替换不同的函数字典,修改起来更灵活。
小提示
你原代码里processC中的problem变量是未定义的,我在示例里假设你是想调用下一个函数并累加值,你可以根据自己的实际需求调整这部分逻辑哦~
内容的提问来源于stack exchange,提问作者Sven Grosen
相关产品推荐
相关产品推荐

