Обработка нелинейных паттернов потребует определения равенства по двум совпадающим терминам.В общем, мы не можем сделать это:
areFunctionsEqual :: (Integer->Integer) -> (Integer->Integer) -> Bool
areFunctionsEqual f f = True
areFunctionsEqual _ _ = False
Вышесказанное не может быть действительно разрешено, поскольку мы не можем сравнивать функции.
Однако можно задаться вопросом, почему это не разрешено длятипы в классе Eq
, где разрешимость не является проблемой.Это позволило бы написать
foo x y x = ...
вместо
foo x y z | z==x = ...
Это сложнее оправдать.Кто-то может утверждать, что первый нелинейный шаблон может быть написан случайно и привносит тонкие ошибки.Второе не так уж и долго, и лучше документирует намерение.
Является ли это хорошим аргументом или нет, это вопрос личного мнения, я думаю.
Еще один тонкий аргумент:
foo x y z | z==x = bar x
денотально эквивалентно
foo x y z | z==x = bar z
, но эти два варианта могут по-прежнему приводить к разным следам памяти, так как в более крупной программе первый из них может позволить z
быть мусоромсобранный, тогда как второй позволил бы x
быть собранным мусором.Если, скажем, z
уже упоминается в другом месте программы, мы хотим использовать вторую форму, чтобы x
собирал мусор.Первая форма привела бы к тому, что и x
, и z
были бы сохранены в памяти.
Если бы мы могли написать foo x y x = bar x
, что будет собирать мусор?Не очень понятно.
Возможно, это очень незначительный момент, поскольку можно все же использовать явный вариант, если управление сборкой мусора так важно.