Почему требуется общая функция

take (-1) [] [].

В чем причины, чтобы предпочесть это по частичной функции, то есть ошибку?

Существуют ли случаи использования этого свойства?

Ответ 1

take и drop аналогичны функциям левой и подстрочной и правой подстрок, и это на практике оказалось удобным для тех, кто не поднимает ошибку для отрицательных или недопустимых длин.

Например, функция заполнения:

pad :: Int -> String -> String
pad n str = (repeat (n - length str) ' ') ++ str

и вот вариант для прокладки с другой строкой:

padWith :: String -> Int -> String -> String
padWith field n str = (take (n - length str) field) ++ str

Ответ 2

Разделение списка в кусках (не более) n штук требует take как итога:

chunks n [] = []
chunks n xs = take n xs : chunks n (drop n xs)

Кроме того, текущее определение гарантирует

take n xs ++ drop n xs == xs

для любых n и xs.

Возможно, мы должны иметь как takeAtMost, так и takeAtLeast, причем последний является частичным вариантом (или вместо этого возвращает Maybe).

Аналогичная озабоченность возникает из zip, которая также является полной, даже если применяется к спискам неравной длины. Тем не менее, это часто используется в idiom zip [1..] xs, который объединяет каждый элемент списка со своим собственным индексом.

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