Давайте начнем с вашей первоначальной реализации:
let rec zip (a , b) =
if List.length a = 1 then List.head a , List.head b
else zip (List.tail a , List.tail b)
Прежде всего, тип неправильный - это возвращает кортеж значений, а не список кортежей. Что он делает, так это то, что он выполняет итерации по списку (следуя хвостам, используя List.tail
), и когда он достигает конца, он возвращает единственный элемент каждого из списков, который является "e"
и 5
.
Первым шагом к исправлению может быть добавление аннотаций типов. Это заставит вас вернуть список в ветке then
. Если у вас есть два одноэлементных списка ["e"]
и [5]
, вы хотите вернуть ["e", 5]
:
let rec zip (a:'a list , b:'b list) : list<'a * 'b> =
if List.length a = 1 then [List.head a , List.head b]
else zip (List.tail a , List.tail b)
Это все еще не правильно - в случае else
вы просто смотрите на хвосты, но вы игнорируете головы. Вам нужно получить доступ к head
и объединить его со списком, возвращаемым из вашего рекурсивного вызова:
let rec zip (a:'a list , b:'b list) : list<'a * 'b> =
if List.length a = 1 then [List.head a , List.head b]
else (List.head a, List.head b) :: zip (List.tail a , List.tail b)
Это работает, но использование if .. then .. else
в этом случае неэлегатно. Ответ Филипе показывает, как сделать это лучше с сопоставлением с образцом.