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

Для чего люди используют функцию идентификации?

Например, Haskell имеет функцию id, у Джулии есть функция identity, и многие вопросы о SO имеют дело с функцией идентификации. (Я полагаю, что в Python вы можете сделать lambda x:x)

Я изрыл свой мозг, пытаясь придумать пример использования этой функции; и я потерпел неудачу.

Какова цель функции идентификации и каковы ее общие случаи использования?

4b9b3361

Ответ 1

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

Например, здесь есть функция, которая отменяет каждый второй элемент списка:

negateEverySecond = zipWith id (cycle [id, negate])

Ответ 2

В Julia (в стандартной библиотеке): быстрый grep показывает, что в настоящее время наиболее популярным использованием функции identity является значение по умолчанию аргумента by для различных связанных с сортировкой функций, таких как sort!, sort, issorted и т.д.

Аргумент by позволяет указать функцию для извлечения ключа сортировки из каждого объекта, так что два объекта a и b сравниваются в соответствии с by(a) < by(b), а не a < b. Функция identity является естественной по умолчанию, так как identity(a) < identity(b) совпадает с a < b.

Существует также внутренний код сортировки, который имеет специальную форму, если by - identity, что должно позволить более эффективный код для общего случая.

Ответ 3

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

foldl f init xs = foldr (\x r -> \acc -> r (f acc x)) id xs $ init

chi упоминает

type K a = (a -> Int) -> Int
-- factorial, CPS
factCPS :: Int -> K Int
factCPS 0 k = k 1
factCPS n k = factCPS (n-1) (k . (*n))

-- factorial, plain
fact :: Int -> Int
fact n = factCPS n id

Этот подход фактически тесно связан с приведенным выше примером; id в определении foldl действительно является продолжением использования.

fact q
  = foldl (*) 1 [1..q]
  = foldr (\x r -> \acc -> r (acc * x)) id (build
      (\c n -> if q<1
               then n
               else let go k | k <= q = k `c` go (k+1)
                             | otherwise = n
                    in go 1)) 1
  -- foldr/build
  = (if q < 1
     then id
     else let go k | k <= q = \acc -> go (k+1) (acc * k)
                   | otherwise = id = \acc -> acc
          in go 1) 1
  = (if q < 1
     then id
     else let go k acc | k <= q = go (k+1) (acc * k)
                       | otherwise = acc
          in go 1) 1
  = if q < 1
    then 1
    else let go k acc | k <= q = go (k+1) (acc*k)
                      | otherwise = acc
         in go 1 1

Ответ 4

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

Другой пример, который я вижу, находится в (id &&& id) - т.е. дублирование элемента в кортеж.

λ> let l = [5,3,4,1]
λ> map (id &&& id) l
[(5,5),(3,3),(4,4),(1,1)]

Ответ 5

Сопоставление списка функций:

compose :: [a -> a] -> a -> a
compose = foldr (.) id
-- to be compared with
sum :: Num a => [a] -> a
sum = foldr (+) 0

Добавление сообщений условно: (не лучшее решение, все еще не так уж плохо)

-- string=""
-- if foo: string += "foo"
-- if bar: string += "bar"
-- print string
putStrLn .
   (if bar then (++"bar") else id) .
   (if foo then (++"foo") else id) $
   ""

Стиль продолжения, базовый регистр:

type K a = (a -> Int) -> Int

-- factorial, CPS
factCPS :: Int -> K Int
factCPS 0 k = k 1
factCPS n k = factCPS (n-1) (k . (*n))

-- factorial, plain
fact :: Int -> Int
fact n = factCPS n id

Ответ 6

Достаточно общая задача - получить значение из Maybe. Мы хотели бы написать

fromMaybe :: a -> Maybe a -> a

хотя это стандартная встроенная функция. Другой стандартной встроенной функцией является Maybe

maybe :: b -> (a -> b) -> Maybe a -> b
maybe nothing just m = case m of
  Nothing -> nothing
  Just a  -> just a

который можно рассматривать как универсальный способ разрушения Maybe -it, просто передает одну функцию для каждой ветки соответствия шаблона.

Наконец, должно быть легко видеть, что fromMaybe и Maybe связаны:

fromMaybe default m = maybe default id m

или в более бесшумном стиле

fromMaybe = flip maybe id

Ответ 7

В принципе, в любое время функция высокого порядка принимает одну или несколько функций в качестве аргументов, но на самом деле вам не нужно выполнять какую-либо работу, вместо этого вы можете передать id.

Я думаю, что кто-то уже упомянул функцию maybe: maybe 0 id заменит Nothing на 0, но если он Just, то мы фактически не хотим изменять данные, просто вернем его. Итак, мы проходим id.

Аналогичная функция const: например, const 7 - это функция, которая принимает один аргумент, полностью игнорирует его и возвращает 7. Почему, черт возьми, вы когда-нибудь захотите этого? Ну, рассмотрим эту реализацию length:

length = sum . map (const 1)

То есть, замените каждый элемент на 1, а затем суммируем их все.

Ответ 8

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

Может случиться так, что сегодня вам нужен конвейер обработки, который работает с вашими исходными данными, поэтому вам не нужна предварительная трансформация на вашем входе (pre_mapping = lambda x : x). В псевдо-питонном коде

 def do_something(data,pre_mapping = lambda x : x)
       data = pre_mapping(data)
       real_foo(data)

возможно, завтра вы поймете, что лучше работать с, например, квадраты данных, и поэтому в строке вы вызываете

 do_something(data
                 , pre_mapping = lambda x : x**2)

Это становится очень полезным, например, если вам нужно попробовать многие из этих pre_mapping s.