Ответ 1
Собственно, этот вопрос более тонкий, чем он может появиться на поверхности, и предполагает немного узнать о внутренних компонентах компилятора, чтобы действительно правильно ответить. Причина в том, что мы считаем само собой разумеющимся, что у нас могут быть вложенные шаблоны и шаблоны более чем на один термин, когда на самом деле для целей компилятора единственное, что вы можете сделать, - это ветвь на конструкторе верхнего уровня одиночного стоимость. Таким образом, первый этап компилятора состоит в том, чтобы превратить вложенные шаблоны (и шаблоны более чем одного значения) в более простые шаблоны. Например, наивный алгоритм может преобразовать вашу функцию в нечто подобное:
myFunc = \x y -> case x of
0 -> case y of
0 -> 0
_ -> x `someoperation` y
1 -> case y of
1 -> 1
_ -> x `someoperation` y
_ -> x `someoperation` y
Здесь вы можете увидеть множество субоптимальных вещей: термин someoperation
многократно повторяется, и функция ожидает оба аргумента, прежде чем он даже начнет вообще делать case
; см. Компилятор соответствия шаблону терминов, вдохновленный теорией конечных автоматов, чтобы обсудить, как вы могли бы улучшить это.
Во всяком случае, в этой форме на самом деле должно быть немного более ясно, как происходит шаг каррирования. Мы можем прямо заменить выражение x
в этом выражении, чтобы посмотреть, что делает myFunc 0
:
myFunc 0 = \y -> case 0 of
0 -> case y of
0 -> 0
_ -> 0 `someoperation` y
1 -> case y of
1 -> 1
_ -> 0 `someoperation` y
_ -> 0 `someoperation` y
Так как это все еще лямбда, дальнейшее сокращение не производится. Вы можете надеяться, что достаточно умный компилятор может сделать немного больше, но GHC явно не делает больше; если вы хотите, чтобы больше вычислений выполнялось после подачи только одного аргумента, вы должны изменить свое определение. (Здесь есть компромисс между временем и пространством и правильным выбором слишком сложно сделать надежно. Поэтому GHC оставляет его в руках программиста, чтобы сделать этот выбор.) Например, вы можете явно писать
myFunc 0 = \y -> case y of
0 -> 0
_ -> 0 `someoperation` y
myFunc 1 = \y -> case y of
1 -> 1
_ -> 1 `someoperation` y
myFunc x = \y -> x `someoperation` y
а затем myFunc 0
уменьшится до гораздо меньшего выражения.