Olhando o Prelúdio de Haskell, vejo uma função const
:
const x _ = x
Não consigo encontrar nada relevante sobre esta função.
Qual é o ponto? Alguém pode dar um exemplo de onde essa função pode ser usada?
Olhando o Prelúdio de Haskell, vejo uma função const
:
const x _ = x
Não consigo encontrar nada relevante sobre esta função.
Qual é o ponto? Alguém pode dar um exemplo de onde essa função pode ser usada?
backgroundColor :: Text -> Color
is for mebackgroundColor = const White
Respostas:
É útil para passar para funções de ordem superior quando você não precisa de toda a flexibilidade. Por exemplo, o operador de sequência monádica
>>
pode ser definido em termos do operador de ligação monádica comoÉ um pouco mais limpo do que usar um lambda
e você pode até mesmo usá-lo sem pontos
embora eu particularmente não recomende isso neste caso.
fonte
map (const 42) [1..5]
resulta em[42, 42, 42, 42, 42]
.const
é útil para aplicar a um único argumento para produzir uma função onde uma é necessária (como passar paramap
).head = foldr const (error "Prelude.head: empty list")
Para adicionar à excelente resposta direta de Hammar: funções humildes gostam
const
eid
são realmente úteis como uma função de ordem superior pela mesma razão que são fundamentais no cálculo combinador de SKI .Não que eu ache que as funções do prelúdio de haskell foram modeladas conscientemente a partir desse sistema formal ou algo assim. É que criar abstrações ricas em haskell é muito fácil, então você frequentemente vê esses tipos de coisas teóricas emergirem como úteis na prática.
Plugue desavergonhado, mas escrevi sobre como a instância Applicative for
(->)
é realmente os combinadoresS
e aqui , se esse é o tipo de coisa que você gosta.K
fonte
((->) e)
também é a mônada do leitor - comReader
e semelhantes sendo apenasnewtype
invólucros - e aask
função é entãoid
, então esse é oI
combinador também. Se você olhar em vez de base BCKW original de Haskell Curry,B
,K
, eW
sãofmap
,return
e,join
respectivamente.Um exemplo simples de uso
const
éData.Functor.(<$)
. Com esta função você pode dizer: eu tenho aqui um functor com algo chato nele, mas ao invés disso eu quero ter aquela outra coisa interessante nele, sem mudar o formato do functor. Por exemploA definição é:
ou escrito não tão sem sentido:
Você vê como
const
é usado aqui para "esquecer" a entrada.fonte
Muitas das outras respostas discutem aplicações relativamente esotéricas (pelo menos para o recém-chegado) de
const
. Aqui está um simples: você pode usarconst
para se livrar de um lambda que leva dois argumentos, joga fora o primeiro, mas faz algo interessante com o segundo.Por exemplo, a seguinte implementação (ineficiente, mas instrutiva) de
length
,pode ser reescrito como
o que talvez seja mais elegante.
A expressão
const (1+)
é na verdade semanticamente equivalente a\_ acc -> 1 + acc
, porque pega um argumento, joga-o fora e retorna a seção(1+)
.fonte
Outro uso é implementar funções de membro de classe que possuem um argumento fictício que não deve ser avaliado (usado para resolver tipos ambíguos). Exemplo que poderia estar em Data.bits:
Ao usar const, dizemos explicitamente que estamos definindo valores constantes.
Pessoalmente, não gosto do uso de parâmetros fictícios, mas se eles forem usados em uma classe, essa é uma maneira bastante boa de escrever instâncias.
fonte
const
pode ser apenas a implementação que você está procurando em conjunto com outras funções. Aqui está um exemplo que descobri.Digamos que queremos reescrever uma estrutura de 2 tuplas em outra estrutura de 2 tuplas. Posso expressar isso assim:
Posso dar uma definição direta com correspondência de padrões:
E se eu quiser uma solução inútil (tácita) para esse tipo de reescrita? Pensando e brincando depois, a resposta é que podemos expressar qualquer reescrita com
(&&&), const, (.), fst, snd
. Observe que(&&&)
é deControl.Arrow
.A solução do exemplo usando essas funções é:
Observe a semelhança com
(a,(c,(5,a)))
. E se substituirmos&&&
por,
? Em seguida, lê-se:Observe como
a
é o primeiro elemento do primeiro elemento e é isso quefst.fst
projeta. Observe comoc
é o primeiro elemento do segundo elemento, e é isso quefst.snd
projeta. Ou seja, as variáveis se tornam o caminho para sua origem.const
nos permite introduzir constantes. Interessante como o nome se alinha com o significado!Eu, então, generalizada esta ideia com Applicative de modo que você pode escrever qualquer função num estilo inútil (contanto que você tem análise de caso disponível como funções, tais como
maybe
,either
,bool
). Novamente,const
desempenha o papel de introduzir constantes. Você pode ver este trabalho no pacote Data.Function.Tacit .Quando você começa abstratamente, no objetivo, e depois trabalha para uma implementação, pode se surpreender com as respostas. Ou seja, qualquer função pode ser tão misteriosa quanto qualquer engrenagem de uma máquina. Se você recuar para visualizar toda a máquina, poderá entender o contexto no qual essa engrenagem é necessária.
fonte
Digamos que você queira criar uma lista
Nothings
igual ao comprimento de uma string. Conformeconst
retorna seu primeiro argumento, não importa o segundo, você pode fazer:ou, mais explicitamente:
fonte
Digamos que você queira girar uma lista. Esta é uma maneira idiomática de fazer isso em Haskell:
rotate :: Int -> [a] -> [a] rotate _ [] = [] rotate n xs = zipWith const (drop n (cycle xs)) xs
Esta função compacta dois arrays com a função
const
, o primeiro sendo um array cíclico infinito, o segundo sendo o array com o qual você começou.const
atua como a verificação de limites e usa a matriz original para encerrar a matriz cíclica.Veja: Rotacionar uma lista em Haskell
fonte
Suponha que você gostaria de gerar todas as subsequências de uma determinada lista.
Para cada elemento da lista, em um determinado ponto, você tem uma escolha de Verdadeiro (inclua-o na subsequência atual) ou Falso (não inclua). Isso pode ser feito usando a função filterM .
Como isso:
Por exemplo, queremos todas as subsequências de
[1..4]
.fonte