List.collect (fun l ->
List.collect (fun ll ->
List.collect (fun lll ->
List.collect id lll
) ll
) l
) [
[[[[[1;3]]]]]
[[[[[2;4]]]]]
]
List.collect (fun ll ->
List.collect (fun lll ->
List.collect id lll
) ll
) [
[[[[1;3]]]]
[[[[2;4]]]]
]
Я хочу иметь что-то для динамической генерации вложенной функции для принятия списка сигнатур разных типов ввода, например списка списков списков int или списка списков списков int, списка списков списков, чтобы получить список списков int
Но при попытке составить такую функцию
let rec llf i ll : 'T list =
let rec f n =
if n = 1 then
fun l ->
List.collect id l
else
fun ln ->
List.collect (llf (n - 1)) ln
f i ll
Там написано
error FS0001: Type mismatch. Expecting a
''T list list'
but given a
''T list'
The types ''T' and ''T list' cannot be unified.
Как я могу исправить свой код?
![Учебная записка [Medium] Leetcode#22 Generate Parentheses](https://i.imgur.com/Hl2feR7b.png)
Возможно, я нашел решение вашей проблемы, но я не думаю, что оно очень элегантное/эффективное, и если у вас есть возможность, я предлагаю вам изменить способ действий (в зависимости от вашего контекста, о котором мы не знаем). ).
В любом случае, во-первых, как указано в комментарии к вашему вопросу, F# статически типизирован и не допускает полиморфизма первого порядка, тем более, когда реализации требуют неопределенного количества случаев (согласно вашему вопросу, вы хотите функция, возвращающая 'a list list независимо от количества вложенных списков).
Таким образом, подход, которому следует следовать, основан на размышлениях и последовательностях в F#, которые практичны для этого стиля использования.
Сначала мы определяем следующую функцию:
let rec flattenSeq (input: seq<obj>) : seq<obj> =
seq {
for item in input do
match item with
| :? seq<obj> as subSeq -> yield! flattenSeq subSeq
| _ -> yield item
}
эта функция будет принимать последовательность объектов (неопределенных типов) и рекурсивно обрабатывать каждый объект, который определяется как последовательность (с помощью «оператора» :?), остальные остаются в обрабатываемой последовательности.
Чтобы использовать эту функцию, вам потребуется box ваши вложенные списки (чтобы преобразовать их в obj). Например,
let example1 = [
box [[[[1; 3]]]]
box [[[[2; 4]]]]
]
let example2 = [
box [[[[[1; 3]]]]]
box [[[[[2; 4]]]]]
]
затем,
let result1 = flattenSeq example1 |> Seq.toList
let result1 = flattenSeq example2 |> Seq.toList
и вы получили ожидаемый результат, потому что «распаковка» выполняется в функции flattenSeq (обратите внимание, что преобразование в список в конце не обязательно, но вы, похоже, работаете со списком).
В этой реализации у вас есть ограничение в виде коробочных списков, как показано на рисунке (в противном случае система типов F# снова вас укусит).
Вы можете адаптировать код к своим потребностям, но у вас всегда будут ограничения системы типов F#, поэтому я думаю, что вы не сможете написать более общую функцию, чем эта.
Проблему, возникающую при унификации типов, можно решить с помощью дискриминируемого объединения. Здесь регистр объединения A содержит значения типа int list, а B отмечает уровни вложенности для удаления, что приводит к int list list в примерах ниже.
type 'a AB =
| A of 'a
| B of 'a AB list
let rec foo xs = [
match xs with
| A y -> yield y
| B ys-> for y in ys do yield! foo y ]
A[1; 2] |> foo
B[A[1; 2]] |> foo
B[B[A[1; 2]]] |> foo
// val it : int list list = [[1; 2]]
B[A[1; 3]; A[2; 4]] |> foo
B[B[A[1; 3]; A[2; 4]]] |> foo
B[B[B[A[1; 3]]; B[A[2; 4]]]] |> foo
B[B[B[B[A[1; 3]]]; B[B[A[2; 4]]]]] |> foo
B[B[B[B[B[A[1; 3]]]]; B[B[B[A[2; 4]]]]]] |> foo
// val it : int list list = [[1; 3]; [2; 4]]
То, что вы хотите сделать, невозможно сделать в F# из-за системы статических типов (или, возможно, я не понял вашей проблемы). Функция, принимающая
int list list list list list, отличается от функции, принимающей'int list list list list list list. Возможно, есть выход с помощьюseqи размышлений, но вместо этого я бы предложил изменить ваш подход, если вы можете.