Почему функция MC Haskell приводит к переполнению стека - PullRequest
3 голосов
/ 18 сентября 2019

Я пробираюсь через книгу на Haskell и занимаюсь 8-й главой. Выполняя упражнения, я заметил кое-что, чего не понял.

Почему это приводит к переполнению стека

mc x | x>100 = x-10
     | otherwise = mc $ mc x+11

но это не

mc x | x>100 = x-10
     | otherwise = mc $ mc (x+11)

Я думаю, что это как-то связано с тем, что x + 11 не вычисляется в первом примере, но не являются ли такие выражения всегда вычисляемыми

например

Prelude> id 43+94
137

Ответы [ 2 ]

6 голосов
/ 18 сентября 2019

Первое выражение

mc $ mc x+11

интерпретируется как

mc ((mc x) + 11)

, поскольку применение функции имеет приоритет над операторами.

Второе выражение

mc $ mc (x+11)

интерпретируется как:

mc (mc (x+11))

Первое действительно никогда не будет оценено, поскольку если вы напишите:

<b>mc x</b> | x > 100 = x-10
     | otherwise = mc (<b>(mc x)</b> + 11)

, тогда вы определите mc x в терминах mc x,До тех пор, пока mc x в этом выражении не будет вычислено, вы, таким образом, будете вызывать mc x при вычислении mc x, и, таким образом, он будет продолжать делать вызовы.

4 голосов
/ 18 сентября 2019

Это чисто о приоритете операторов.В частности, применение функции имеет приоритет над всеми операторами.Итак, это:

mc x+11

фактически анализируется как

(mc x)+11

, и тот факт, что вы пытались «визуально» указать желаемую группировку через интервал или ее отсутствие, не имеет значения.Именно поэтому ваша вторая версия работает лучше, поскольку вы явно указали желаемую группировку.

Конечно, непреднамеренная интерпретация означает, что для x <= 100 для оценки mc x компилятор имеетсначала оценить mc x и так до бесконечности.Отсюда возможное переполнение стека.

...