Ответ 1
Короткий ответ: да, указатель поддерживается до 2
, пока не пройдет 4
.
Дольше необходимого ответа:
Концептуально, вы должны думать о том, что Haskell определяется с точки зрения исчисления лямбда и переписывания терминов. Допустим, у вас есть следующее определение:
f x y = x + y
Это определение для f
появляется в лямбда-исчислении как нечто вроде следующего, где я явно помещал круглые скобки вокруг лямбда-тел:
\x -> (\y -> (x + y))
Если вы не знакомы с исчислением лямбда, это в основном говорит "функция аргумента x
, которая возвращает (функция аргумента y
, которая возвращает (x + y
))". В исчислении лямбда, когда мы применяем такую функцию к некоторому значению, мы можем заменить применение функции копией тела функции со значением, замененным для параметра функции.
Итак, выражение f 1 2
оценивается с помощью следующей последовательности перезаписи:
(\x -> (\y -> (x + y))) 1 2
(\y -> (1 + y)) 2 # substituted 1 for x
(1 + 2) # substituted 2 for y
3
Итак, вы можете видеть здесь, что если бы мы предоставили только один аргумент f
, мы остановились бы на \y -> (1 + y)
. Таким образом, у нас есть целый термин, который является просто функцией добавления 1 к чему-то, полностью отделенному от нашего первоначального термина, который все еще может быть использован где-то (для других ссылок на f
).
Ключевым моментом является то, что если мы реализуем такие функции, каждая функция имеет только один аргумент, но некоторые возвращаемые функции (и некоторые возвращаемые функции, возвращающие возвращаемые функции...). Каждый раз, когда мы применяем функцию, мы создаем новый термин, который "жестко кодирует" первый аргумент в тело функции (включая тела любых функций, которые он возвращает). Вот как вы получаете карри и закрытие.
Теперь, это не так, как Haskell непосредственно реализуется, очевидно. Когда-то давно Хаскелл (или, возможно, один из его предшественников, я не совсем уверен в истории) был реализован Сокращение графика. Это метод для того, чтобы сделать что-то эквивалентное сокращению термина, описанному выше, что автоматически дает ленивую оценку и справедливое количество обмена данными.
В сокращении графика все ссылки на узлы в графе. Я не буду вдаваться в подробности, но когда механизм оценки уменьшает применение функции до значения, она копирует подграфик, соответствующий телу функции, с необходимой заменой значения аргумента для параметра функции (но разделяет ссылки на узлы графа, где они не подвержены замене). Таким образом, по существу, да, частично применение функции создает новую структуру в памяти, которая ссылается на предоставленный аргумент (то есть "указатель на 2
), и ваша программа может передавать ссылки на эту структуру (и даже делиться ею и применяйте его несколько раз), пока не будет предоставлено больше аргументов, и это может быть фактически уменьшено. Однако не похоже, что он просто запоминает функцию и накапливает аргументы, пока не получит все из них: механизм оценки фактически выполняет некоторую работу каждый раз, когда он применяется к новому аргументу. На самом деле механизм сокращения графа не может даже отличить приложение, которое возвращает функцию, и все еще нуждается в большем количестве аргументов, и тот, у которого только что появился последний аргумент.
Я не могу рассказать вам больше о текущей реализации Haskell. Я считаю, что это далекий мутантный потомок сокращения графа, с множеством умных коротких сокращений и быстрых полос. Но я могу ошибаться в этом; возможно, они нашли совершенно другую стратегию исполнения, которая больше не похожа на сокращение графика. Но я на 90% уверен, что он все равно закончит работу над структурами данных, которые держатся за ссылки на частичные аргументы, и, вероятно, он все же частично делает что-то эквивалентное факторингу в аргументах, так как кажется довольно важным, чтобы ленивая оценка работает. Я также уверен, что он будет делать множество оптимизаций и коротких сокращений, поэтому, если вы прямо вызываете функцию из 5 аргументов, таких как f 1 2 3 4 5
, она не пройдет через все трудности, связанные с копированием тела f 5 раз подряд более "жесткого кодирования".