Haskell Семантика вызова по имени / значению - PullRequest
0 голосов
/ 04 мая 2020

Я новичок в Haskell, у меня есть вопрос

h x = x : (h x)
g xs = [head xs, head xs - 1]

Каков результат выполнения g(h 2) при условии, что семантика - это вызов по имени и вызов по значению?

Ответы [ 2 ]

3 голосов
/ 05 мая 2020

«Вызов по имени» - это стратегия нестрогой оценки без запоминания где значение (значения) аргумента (ов) нужно найти только при фактическом использовании внутри тело функции, каждый раз заново:

h x = x : (h x)
g xs = [head xs, head xs - 1]

g (h 2) = let {xs = (h 2)} in [head xs, head xs - 1]
        = [let {xs = (h 2)} in head xs, let {xs = (h 2)} in head xs - 1]
        = [head (h 2),                  let {xs = (h 2)} in head xs - 1]
        = [head (let {x = 2} in x : (h x)}), let {xs = (h 2)} in head xs - 1]
        = [let {x = 2} in x,            let {xs = (h 2)} in head xs - 1]
        = [2,                           let {xs = (h 2)} in head xs - 1]
        = ....

«Вызов по необходимости» - это запоминание нестрогой или «ленивой» стратегии оценки где значение (значения) аргумента (ов) должны быть найдены только при использовании внутри тела функции в первый раз , а затем доступны для дальнейшего использования:

h x = x : (h x)
g xs = [head xs, head xs - 1]

g (h 2) = let {xs = (h 2)}       in [head xs, head xs - 1]
        = let {xs = (2 : (h 2))} in [head xs, head xs - 1]
        = let {xs = (2 : (h 2))} in [2,       head xs - 1]
        = ....

«Вызов по значению» - это строгая оценка стратегия , где значение (а) аргумента (ов) должно быть найдено до ввода тела функции:

h x = x : (h x)
g xs = [head xs, head xs - 1]

g (h 2) = let {xs = (h 2)} in [head xs, head xs - 1]
        = let {xs = (2 : (h 2))} in [head xs, head xs - 1]
        = let {xs = (2 : (2 : (h 2)))} in [head xs, head xs - 1]
        = let {xs = (2 : (2 : (2 : (h 2))))} in [head xs, head xs - 1]
        = ....

Все вышеперечисленное предполагает, что g (h 2) вводится в приглашение GHCi, поэтому оно должно быть распечатано полностью.

0 голосов
/ 04 мая 2020

Давайте go пошагово.

Прежде всего, h x = x : (h x) рекурсивен. Функция h определяется в терминах самой себя: при некотором x она помещает ее в list, что составляет x : x : x : ... бесконечность. Другими словами, поскольку повторный курс никогда не заканчивается, список не может быть конечным. Но это не висит вечно. Почему?

Потому что Haskell ленивый. Он не оценивает никаких выражений, кроме абсолютно необходимых. В вашем случае в памяти вообще не создается бесконечных списков, вызывается событие if h 2. Почему?

Потому что g запрашивает только два первых элемента данного списка с именем xs. Haskell достаточно умен, чтобы расширять бесконечный список только на столько, сколько необходимо, и не тратить ресурсы впустую. В общем, это преимущество лени. Он также работает с другими выражениями, а не только со списками.

...