Рекусивное сканирование через иерархию списка различных типов записей
У меня есть структура данных, которая состоит из списка записей 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
1 ответ
Чтобы решить проблему, вам нужно сопоставить что-то типа obj
а не на значение неопределенного типа (параметр типа 'a
). Вы можете сделать это, добавив box
:
match box head with
| :? MarshallingPanel as marshallingPanel ->
mapAsRequired marshallingPanel.PLCs currentCBMap
| :? PLC as plc ->
mapAsRequired plc.Racks currentCBMap
Однако я полностью согласен с замечанием Джона Палмера о том, что использование дискриминационного союза кажется лучшим выбором для вашей цели.