9 ответов
Это полезно в качестве аргумента для функций более высокого порядка (функций, которые принимают функции в качестве аргументов), где вы хотите, чтобы какое-то конкретное значение оставалось неизменным.
Пример 1. Оставьте значение в покое, если оно находится в Just, в противном случае верните значение по умолчанию, равное 7.
Prelude Data.Maybe> :t maybe
maybe :: b -> (a -> b) -> Maybe a -> b
Prelude Data.Maybe> maybe 7 id (Just 2)
2
Пример 2: построение функции с помощью сгиба:
Prelude Data.Maybe> :t foldr (.) id [(+2), (*7)]
:: (Num a) => a -> a
Prelude Data.Maybe> let f = foldr (.) id [(+2), (*7)]
Prelude Data.Maybe> f 7
51
Мы построили новую функцию f
сложив список функций вместе с (.)
, с помощью id
в качестве базового варианта.
Пример 3: базовый случай для функций в виде моноидов (упрощенно).
instance Monoid (a -> a) where
mempty = id
f `mappend` g = (f . g)
Как и в нашем примере с Fold, функции могут рассматриваться как объединяемые значения с id
служит для пустого дела, и (.)
как добавить.
Пример 4: тривиальная хеш-функция.
Data.HashTable> h <- new (==) id :: IO (HashTable Data.Int.Int32 Int)
Data.HashTable> insert h 7 2
Data.HashTable> Data.HashTable.lookup h 7
Just 2
Hashtables требуют хеш-функции. Но что, если ваш ключ уже хэширован? Затем передайте функцию id, чтобы заполнить ее как метод хеширования, с нулевыми накладными расходами.
Если вы манипулируете числами, особенно с помощью сложения и умножения, вы заметите полезность 0 и 1. Аналогично, если вы манипулируете списками, пустой список оказывается весьма удобным. Точно так же, если вы манипулируете функциями (что очень часто встречается в функциональном программировании), вы заметите такую же полезность id
,
В функциональных языках функции - это значения первого класса, которые вы можете передать в качестве параметра. Так что одно из самых распространенных применений id
появляется, когда вы передаете функцию в качестве параметра другой функции, чтобы сказать ей, что делать. Один из вариантов того, что делать, скорее всего, будет "просто оставить это в покое" - в этом случае вы передаете id
в качестве параметра.
Предположим, вы ищете какое-то решение головоломки, в которой вы делаете ход на каждом ходу. Вы начинаете с позиции кандидата pos
, На каждом этапе есть список возможных преобразований, которые вы могли бы сделать pos
(например, скольжение кусок в головоломке). На функциональном языке естественно представлять преобразования как функции, поэтому теперь вы можете составить список ходов, используя список функций. Если "ничего не делать" является законным ходом в этой головоломке, то вы должны представить это с id
, Если вы этого не сделали, то вам нужно было бы рассматривать "бездействие" как особый случай, который работает иначе, чем "делать что-то". Используя id
Вы можете обрабатывать все случаи единообразно в одном списке.
Это, вероятно, причина, почему почти все виды использования id
существовать. Чтобы справиться с "ничего не делая" равномерно с "делать что-то".
Так как мы находим хорошие приложения id
, Здесь есть палиндром:)
import Control.Applicative
pal :: [a] -> [a]
pal = (++) <$> id <*> reverse
Я также могу помочь улучшить ваш счет в гольф. Вместо того, чтобы использовать
($)
Вы можете сохранить один символ, используя идентификатор.
например
zipWith id [(+1), succ] [2,3,4]
Интересный, более чем полезный результат.
Для другого вида ответа:
Я часто делаю это при объединении нескольких функций в композицию:
foo = id
. bar
. baz
. etc
над
foo = bar
. baz
. etc
Это облегчает редактирование. Можно делать подобные вещи с другими "нулевыми" элементами, такими как
foo = return
>>= bar
>>= baz
foos = []
++ bars
++ bazs
Представьте, что вы компьютер, то есть вы можете выполнить последовательность шагов. Тогда, если я хочу, чтобы вы оставались в вашем текущем состоянии, но я всегда должен давать вам инструкции (я не могу просто отключить звук и позволить времени пройти), какую инструкцию я вам даю? Идентификатор - это функция, созданная для этого, для возврата аргумента без изменений (в случае предыдущего компьютера аргументом будет его состояние) и для наличия имени для него. Эта необходимость возникает только тогда, когда у вас есть функции высокого порядка, когда вы работаете с функциями без учета того, что внутри них, что заставляет вас символически представлять даже реализацию "ничего не делать". Аналогично 0, рассматриваемый как количество чего-либо, является символом отсутствия количества. На самом деле в алгебре и 0, и id считаются нейтральными элементами операций + и ∘ (состав функции) соответственно, или более формально:
для всех х типа номер:
- 0 + х = х
- х + 0 = х
для всех функций типа f:
- id ∘ f = f
- f ∘ id = f
Всякий раз, когда вам нужно где-то иметь функцию, но вы хотите сделать больше, чем просто удерживать ее место (например, "undefined").
Это также полезно, как упоминал выше доктор Стюарт (для будущего), когда вам нужно передать функцию в качестве аргумента другой функции:
join = (>>= id)
или как результат функции:
let f = id in f 10
(предположительно, вы отредактируете вышеупомянутую функцию позже, чтобы сделать что-то более "интересное"...;)
Как уже упоминали другие, id
является прекрасным заполнителем для тех случаев, когда вам нужна функция где-то.