【发布时间】:2020-02-01 10:33:38
【问题描述】:
我有一个数据结构,它由一个 F# 记录列表组成,其中一个成员本身是一个不同类型的记录列表,直到大约 4 级深层次结构。我必须创建这个结构的代码有点冗长但有效。我现在希望创建一个通用的尾递归函数,该函数从层次结构的顶层分解此数据结构的列表,以生成一个映射,该映射是层次结构列表底层中项目数的计数。我可以通过创建函数来开发所需的代码来分解层次结构中每个级别的记录,但最终你会得到相同的递归函数来处理列表,但记录类型不同。以下是我尝试以非详细方式实现此功能的方法,但出现以下错误:
此运行时强制或来自类型的类型测试
'a
到MarshallingPanel
涉及基于此程序点之前的信息的不确定类型。某些类型不允许运行时类型测试。
我了解错误是 F# 中的类型推断,并且我可以找到的类型测试模式匹配示例涉及基类引用或可区分联合。我将尝试一个联合,如果这不起作用,请详细说明,但如果你们中的任何一个 F# 大师有要遵循的模式或任何输入都会很棒。
let rec mapAsRequired items (currentCBMap: Map<string*string*string*string, int>) =
match items with
| head :: tail ->
match head with
| :? MarshallingPanel as marshallingPanel ->
mapAsRequired marshallingPanel.PLCs currentCBMap
| :? PLC as plc ->
mapAsRequired plc.Racks currentCBMap
| :? Rack as rack ->
mapAsRequired rack.Slots currentCBMap
| _ ->
mapAsRequired [] currentCBMap
mapAsRequired tail currentCBMap
| [] ->
currentCBMap
let rec mapMarshallingPanels (marshallingPanels:MarshallingPanel list) (currentCBMap: Map<string*string*string*string, int>) =
match marshallingPanels with
| head :: tail ->
mapMarshallingPanels tail (mapAsRequired (List.sortBy(fun (plc:PLC) -> rankProcessorForCBAlllocation plc.PLCNo) head.PLCs) currentCBMap)
| [] ->
currentCBMap
mapAsRequired marshallingPanels Map.empty
【问题讨论】:
-
这对于 DU 来说绝对是一个很好的例子——你应该尽量避免
:? ...模式匹配,因为它往往表明你没有很好地使用类型系统 -
我目前怀疑我的问题是我对原始数据结构的实现。我怀疑我需要使用 DU 或递归类型创建原始数据结构,该数据结构提供给我可以递归调用的单个通用列表成员。将现有的 Record 类型包装到 DU 中提供了一种递归执行模式匹配的方法,但当前数据结构仅返回特定类型记录的列表。通过类型推断递归函数需要一个 DU 包装器列表。感谢您的帮助。
标签: f# tail-recursion