Первый вопрос: почему тип выглядит как ('a list * 'a list list)
, это потому, что вывод типа просматривает эту часть кода:
| helper2(a::l1,b::l2) =l1::l2
^^
here
Имейте в виду, что тип "cons"Оператор (::
) - 'a -> 'a list -> 'a list
, он склеивает отдельный элемент в список элементов того же типа.Таким образом, SML пришел к выводу, что, независимо от того, что l1
и l2
, существует связь, что l2
является списком того, что есть l1
.
fun helper2(nil,b) = []
Говорит, что a
должен быть спискомпотому что nil
имеет тип 'a list
.Следовательно, l2
должен быть списком списков (некоторого типа 'a
).
Вопрос 2 и 3: Я не совсем уверен, как исправить код, как он написан.Я бы, наверное, написал что-то вроде этого:
fun helper2 [] accum = List.rev accum
| helper2 ((a,b)::tl) accum = helper2 tl (b :: a :: accum);
fun flatten2 list = helper2 list [];
helper2
выполняет всю грязную работу.Если список ввода пуст, то мы все сделали, и мы можем вернуть инвертированный аккумулятор , который мы строили.Во втором случае мы добавляем вещи в аккумулятор.Мы сопоставляем образец по голове и хвосту списка.Это сопоставление с образцом означает, что вход имеет тип ('a * 'a) list
(список кортежей, в которых оба элемента имеют одинаковый тип).В голове у нас есть кортеж, и мы называем первый и второй элементы a
и b
соответственно.Мы добавляем a
, затем b
в аккумулятор и рекурсивно вызываем helper2
в конце списка.В конце концов, мы пройдемся по всем элементам в списке, а затем останемся только с аккумулятором, который, напомним, содержит все элементы, но в обратном порядке.Вызов List.rev
переворачивает аккумулятор, и это наш ответ.
И когда я загружаю и запускаю его, я получаю это:
- flatten2 [(1,2), (3,4), (5,6)];
val it = [1,2,3,4,5,6] : int list