В функциональном мире списки неизменны. Это означает, что совместное использование узла возможно, потому что исходные списки никогда не изменятся. Поскольку первый список заканчивается пустым списком, его узлы должны быть скопированы, чтобы указать свой последний узел на второй список. После операции добавления наши списки выглядят так:
В этот момент, более скептически вы можете сказать: "Ну,
это довольно интересная теория, но можете ли вы доказать это? "
Нет проблем.
Используя знание того, что списки F # являются рекурсивными, мы можем получить
последняя половина комбинированного (внутренний список начинается с 4), взяв
хвост, хвоста, хвоста. List.tl это функция, которая F #
обеспечивает извлечение хвоста списка.
> let lastHalf = List.tl (List.tl (List.tl combined));;
val lastHalf : int list
> lastHalf;;
val it : int list = [4; 5; 6]
Наконец, поскольку F # является первоклассным гражданином .NET Framework, мы
иметь полный доступ ко всем библиотекам базовых классов. Итак, мы можем использовать
Object.ReferenceEquals
метод для проверки, является ли lastHalf
а второй действительно один и тот же экземпляр.
> System.Object.ReferenceEquals(lastHalf, second);;
val it : bool = true
И вот оно у вас. Хотите верьте, хотите нет, добавляя два неизменных
списки могут быть быстрее и эффективнее, чем добавление
изменяемые списки, потому что нужно копировать меньше узлов.