Просматривая Haskell Prelude, я вижу функцию const
:
const x _ = x
Я не могу найти ничего подходящего относительно этой функции.
В чем смысл? Кто-нибудь может привести пример, где можно использовать эту функцию?
Просматривая Haskell Prelude, я вижу функцию const
:
const x _ = x
Я не могу найти ничего подходящего относительно этой функции.
В чем смысл? Кто-нибудь может привести пример, где можно использовать эту функцию?
backgroundColor :: Text -> Color
это для меняbackgroundColor = const White
Ответы:
Это полезно для перехода к функциям более высокого порядка, когда вам не нужна их гибкость. Например, оператор монадической последовательности
>>
может быть определен в терминах оператора монадического связывания какx >> y = x >>= const y
Это немного удобнее, чем использование лямбды
x >> y = x >>= \_ -> y
и вы даже можете использовать его бесплатно
хотя я не особо рекомендую это в данном случае.
источник
map (const 42) [1..5]
получается[42, 42, 42, 42, 42]
.const
полезен для применения к одному аргументу, чтобы получить функцию там, где он нужен (например, переход кmap
).head = foldr const (error "Prelude.head: empty list")
Чтобы добавить к отличному прямому ответу Хаммара: скромные функции, такие как
const
иid
, действительно полезны как функции высшего порядка по той же причине, по которой они являются фундаментальными в исчислении комбинатора SKI .Не то чтобы я думаю, что вступительные функции haskell были сознательно смоделированы после этой формальной системы или чего-то еще. Просто создать богатые абстракции в haskell очень просто, поэтому вы часто видите, что подобные теоретические вещи оказываются практически полезными.
Shameless плагин, но я писал о том , как Аппликативный экземпляр для
(->)
фактически являютсяS
иK
комбинаторы здесь , если это такая вещь , вы в.источник
((->) e)
это также монада читателя - сReader
и тому подобное, просто являющиесяnewtype
оболочками - иask
функция тогдаid
, так что это тожеI
комбинатор. Если вы посмотрите на оригинальный вместо BCKW основе Хаскелла Карри,B
,K
иW
являютсяfmap
,return
иjoin
соответственно.Простой пример использования
const
-Data.Functor.(<$)
. С помощью этой функции вы можете сказать: у меня есть функтор с чем-то скучным, но вместо этого я хочу иметь в нем еще одну интересную вещь, не меняя форму функтора. Напримерimport Data.Functor 42 <$ Just "boring" --> Just 42 42 <$ Nothing --> Nothing "cool" <$ ["nonsense","stupid","uninteresting"] --> ["cool","cool","cool"]
Определение таково:
или написано не как бессмысленное:
cool <$ uncool = fmap (const cool) uncool
Вы видите, как
const
здесь используется, чтобы «забыть» о вводе.источник
Во многих других ответах обсуждаются относительно эзотерические (по крайней мере, для новичков) приложения
const
. Вот простой: вы можете использовать,const
чтобы избавиться от лямбды, которая принимает два аргумента, отбрасывает первый, но делает что-то интересное со вторым.Например, следующая (неэффективная, но поучительная) реализация
length
,length' = foldr (\_ acc -> 1 + acc) 0
можно переписать как
length' = foldr (const (1+)) 0
что, возможно, более элегантно.
Выражение
const (1+)
действительно семантически эквивалентно\_ acc -> 1 + acc
, потому что оно принимает один аргумент, отбрасывает его и возвращает раздел(1+)
.источник
Другое использование - реализация функций-членов класса, которые имеют фиктивный аргумент, который не должен оцениваться (используется для разрешения неоднозначных типов). Пример, который может быть в Data.bits:
instance Bits Int where isSigned = const True bitSize = const wordSize ...
Используя const, мы явно говорим, что определяем постоянные значения.
Лично мне не нравится использование фиктивных параметров, но если они используются в классе, это довольно хороший способ написания экземпляров.
источник
const
может быть просто реализацией, которую вы ищете в сочетании с другими функциями. Вот пример, который я обнаружил.Скажем, мы хотим переписать структуру из двух кортежей в другую структуру из двух кортежей. Я могу выразить это так:
((a,b),(c,d)) ⇒ (a,(c,(5,a)))
Я могу дать прямое определение с сопоставлением с образцом:
f ((a,b),(c,d)) = (a,(c,(5,a)))
Что, если мне нужно бессмысленное (неявное) решение для такого рода переписываний? Подумав немного позже, ответ в том, что мы можем выразить любые переписывания с помощью
(&&&), const, (.), fst, snd
. Обратите внимание, что(&&&)
это изControl.Arrow
.Решение примера с использованием этих функций:
(fst.fst &&& (fst.snd &&& (const 5 &&& fst.fst)))
Обратите внимание на сходство с
(a,(c,(5,a)))
. Что если заменить&&&
на,
? Затем он гласит:(fst.fst, (fst.snd, (const 5, fst.fst)))
Обратите внимание на то, как
a
выглядит первый элемент первого элемента, и это то, чтоfst.fst
проецируется. Обратите внимание, какc
выглядит первый элемент второго элемента, и это то, чтоfst.snd
проецируется. То есть переменные становятся путем к своему источнику.const
позволяет нам вводить константы. Интересно, как название сочетается со смыслом!Затем я обобщил эту идею с Applicative , так что вы можете написать какую - либо функцию в бессмысленном стиле (до тех пор , пока у вас есть случай анализ доступен как функции, такие как
maybe
,either
,bool
). Опять же,const
играет роль введения констант. Вы можете увидеть эту работу в пакете Data.Function.Tacit .Когда вы начинаете абстрактно с цели, а затем работаете над реализацией, вы можете быть удивлены ответами. Другими словами, любая функция может быть такой же загадочной, как и любой винтик в машине. Однако, если вы отодвинетесь, чтобы увидеть всю машину, вы сможете понять контекст, в котором этот винтик необходим.
источник
Допустим, вы хотите создать список,
Nothings
равный длине строки. Asconst
возвращает свой первый аргумент, независимо от второго, вы можете:listOfNothings :: String -> [Maybe Char] listOfNothings = (map . const) Nothing
или, точнее:
listOfNothing st = map (const Nothing) st
источник
Допустим, вы хотите повернуть список. Это идиоматический способ сделать это в Haskell:
rotate :: Int -> [a] -> [a] rotate _ [] = [] rotate n xs = zipWith const (drop n (cycle xs)) xs
Эта функция объединяет два массива с функцией
const
, первый из которых представляет собой бесконечный циклический массив, а второй - это массив, с которого вы начали.const
действует как проверка границ и использует исходный массив для завершения циклического массива.См .: Поворот списка в Haskell
источник
Предположим, вы хотите сгенерировать все подпоследовательности данного списка.
Для каждого элемента списка в определенный момент у вас есть выбор: True (включить его в текущую подпоследовательность) или False (не включать). Это можно сделать с помощью функции filterM .
Как это:
λ> import Control.Monad λ> :t filterM filterM :: Applicative m => (a -> m Bool) -> [a] -> m [a] λ>
Например, нам нужны все подпоследовательности
[1..4]
.λ> filterM (const [True, False]) [1..4] [[1,2,3,4],[1,2,3],[1,2,4],[1,2],[1,3,4],[1,3],[1,4],[1],[2,3,4],[2,3],[2,4],[2],[3,4],[3],[4],[]] λ>
источник