Количество аргументов и отсутствие точек в Haskell

При множественном сопоставлении шаблонов различное количество аргументов невозможно, даже без точечного!

foo True b = b + 2
foo _ = id

не работает, например. Но

foo True = (+2)
foo _ = id

делает. Иногда мы можем использовать point-free только в одной части функции, поэтому...

Почему? Это слишком сложно для GHC?: '(

Ответы

Ответ 1

Почему? Это слишком сложно для GHC?

Нет. Для GHC это не слишком сложно. Фактически, это ошибка отчета Haskell.

Смотрите: Haskell Report 2010 > Объявления и привязки > привязки функций

Связывание функции связывает переменную с значением функции. Общая форма связывания функции для переменной x:

x p1 1... p1 k match1
...
x pn 1... pn k matchn

[... бла-бла...]

Перевод: общая форма привязки для функций является семантически эквивалентной к уравнению (т.е. простому привязке шаблона):

x =\x 1... x k → case (x 1,..., x k)

(p11,..., p1k) match1
...
(pn1,..., pnk) matchn
где x i - новые идентификаторы.

(акцент мой)

Хотя определения функций семантически эквивалентны выражению лямбда и case, они не обязательно собираются таким образом, как предполагает Михай.

Дело в том, что отчет Haskell определяет объявления функций, так что они должны иметь одинаковое количество входов в левой части уравнения. Это подтверждается тем фактом, что k остается неизменным как в первой, так и в первой строках объявления функции (и подразумевается, все линии между ними). Это и есть причина ограничения; он не имеет ничего общего с деталями реализации GHC.

ТЛ; дг

Выбор не допускать этого - это просто вопрос стиля. - augustss

Ответ 2

Каждое уравнение функции должно иметь одинаковое количество аргументов. Вот почему ваш первый пример не работает.

Чтобы исправить это, используйте

foo True b = b + 2
foo _ x = id x

Как вы видите, оба уравнения имеют одинаковое количество аргументов.

Несколько уравнений, связанных с сопоставлением шаблонов, переводятся в выражения case. В вашем случае foo будет транслироваться примерно как

foo a b = case a of
    True -> b + 2
    _ -> id x

Обе (все) ветки case должны иметь один и тот же тип, таким образом, вы первый пример, который будет переведен как

foo a b = case a of
    True -> b + 2
    _ -> id

неверно, потому что ветки имеют разные типы.

Конечно, это ручная махать, реальные вещи, происходящие за кулисами, сложнее.