Подтвердить что ты не робот

Есть ли веская причина, почему `deleteBy` не имеет своего самого общего типа?

В отчете по языку языка Haskell 2010 в разделе 20.10.1.1 указано, что:

deleteBy :: (a -> a -> Bool) -> a -> [a] -> [a]

Фактически, реализация в библиотеке

потому что Int не совпадает с (Int, String).

Есть ли веская причина для этого?

Причина, по которой я спрашиваю, заключается в том, что если нет веских оснований для этого, я бы включил deleteBy с более общим типом в порт Data.List, который я сейчас делаю. Но, может быть, я что-то пропускаю?

EDIT: Как отметил @hammar, это относится и к другим функциям xxxBy.

4b9b3361

Ответ 1

Обобщение типа deleteBy очень сильно нарушает стандарт: совершенно допустимые программы Haskell становятся недействительными благодаря нерешенной перегрузке.

Здесь демонстрация:

class (Num a) => Magic a where
  magic :: a -> Bool

sameMagic :: (Magic a, Magic b) => a -> b -> Bool
sameMagic a b = magic a == magic b

test :: (Magic a) => [a]
test = deleteBy sameMagic 42 [1234]

В Haskell эта программа отлично набрана; deleteBy ограниченный тип гарантирует, что 42 будет иметь тот же тип, что и 1234. С обобщенным deleteBy это не так, поэтому тип 42 неоднозначен, что делает программу недействительной. (Если вы хотите использовать менее надуманный пример, рассмотрите функцию, которая сравнивает два значения Integral с toInteger.)

Итак, возможно, нет веских оснований для этого ограниченного типа (хотя, если deleteBy должен быть обобщен, я бы предпочел вариант хаммар для вашего предложения), но обобщение его нарушает стандарт и может разорвать действительные программы.

Ответ 2

Я предполагаю это для симметрии с другими функциями xxxBy. Однако ваш тип по-прежнему бесполезен. Я бы предпочел это.

deleteBy :: (a -> Bool) -> [a] -> [a]

Затем вы можете написать свой пример с помощью частичного приложения:

foo = deleteBy (fsteq 42) [(43, "foo"), (44, "bar"), (42, "baz")] where
    fsteq a (b,_) = a == b

Ответ 3

Инго,

в вашем исходном вопросе, кажется, вы спрашиваете, почему Haskell Report указывает deleteBy, как это. Поэтому, если нет веских оснований, вы можете использовать другое определение в Фреге (подразумевая, что вы не заботитесь о соответствии Haskell Report).

Как говорит Хаммар, он похож на другие функции xxxBy: delete uses (==), deleteBy принимает предикат, похожий на (==): типа (a → a → Bool) и считается эквивалентным связь. Хотя система типов не может проверить, является ли предикат действительно отношением эквивалентности, это функция контракта. Поэтому очень легко понять, что означает xxxBy, если вы знаете, что означает xxx. И, возможно, это не так для deleteBy, но в некоторых случаях реализация может быть оптимизирована в предположении, что предикат имеет указанные свойства (отношение эквивалентности или общий порядок и т.д.).

Но в своем комментарии к Хаммару ответ вы спрашиваете, приведет ли более общая реализация к нарушению отчета. Ну, если тип отличается, то это буквально нарушение, не так ли? Поскольку программы, которые не должны компилироваться в соответствии с отчетом, будут приняты вашим компилятором. Таким образом, это приводит к проблеме переносимости: если ваш код использует более общую версию, он может не компилироваться в другой реализации, соответствующей спецификации. Кроме того, он устраняет требование отношения эквивалентности.

Итак, если вы хотите более общую функцию, почему бы просто не определить другую функцию с другим именем? Например, deleteIf.

(Я хотел прокомментировать ответ Хаммара, но я не могу, поэтому написал его здесь.)