¿Cuál es el sentido de 'const' en Haskell Prelude?

92

Al mirar a través del Preludio de Haskell, veo una función const :

const x _ = x

Parece que no puedo encontrar nada relevante con respecto a esta función.

¿Cuál es el punto de? ¿Alguien puede dar un ejemplo de dónde podría usarse esta función?

herrero
fuente
10
Un ejemplo: backgroundColor :: Text -> Colores para míbackgroundColor = const White
Zhen

Respuestas:

83

Es útil para pasar a funciones de orden superior cuando no necesita toda su flexibilidad. Por ejemplo, el operador de secuencia monádica >>se puede definir en términos del operador de unión monádica como

x >> y = x >>= const y

Es algo más ordenado que usar una lambda.

x >> y = x >>= \_ -> y

e incluso puedes usarlo sin puntos

(>>) = (. const) . (>>=)

aunque no lo recomiendo particularmente en este caso.

Hammar
fuente
9
+1. También aparece con frecuencia cuando se utilizan combinadores de analizadores sintácticos.
Fred Foo
47
Ahh, entonces es más un 'generador de funciones': lo uso con un argumento y me da una función (tomando un argumento) que siempre devuelve un valor constante. Entonces map (const 42) [1..5]resulta en [42, 42, 42, 42, 42].
stusmith
2
stusmith: Lo tienes. constes útil para aplicar a un solo argumento para producir una función donde se necesita una (como pasar a map).
Conal
8
@stusmith: Se puede utilizar en algunos aspectos interesantes:head = foldr const (error "Prelude.head: empty list")
rampion
27

Para agregar a la excelente respuesta directa de Hammar: las funciones humildes como consty idson realmente útiles como una función de orden superior por la misma razón que son fundamentales en el cálculo del combinador de SKI .

No es que crea que las funciones de preludio de Haskell fueron modeladas conscientemente a partir de ese sistema formal o algo así. Es solo que crear abstracciones ricas en Haskell es muy fácil, por lo que a menudo ves que este tipo de cosas teóricas surgen como prácticamente útiles.

Enchufe descarado, pero escribí en un blog sobre cómo la instancia de Applicative para (->)son en realidad los combinadores Sy aquí , si ese es el tipo de cosas que te gustan.K

jberryman
fuente
8
Bueno, los combinadores de SKI ciertamente influyeron en el Preludio. Recuerdo haber discutido con Joe Fasel si el combinador S debería incluirse o no.
2011
4
Por cierto, ((->) e)también es la mónada del lector, con Readery similares simplemente newtypeenvoltorios, y la askfunción es entonces id, por lo que también es el Icombinador. Si nos fijamos en su lugar en base BCKW original del Haskell Curry, B, K, y Wson fmap, returny joinrespectivamente.
CA McCann
1
El enlace del blog en la respuesta está muerto. Ahora debería apuntar aquí: brandon.si/code/…
nsxt
22

Un ejemplo sencillo de uso constes Data.Functor.(<$). Con esta función puedes decir: Tengo aquí un funtor con algo aburrido, pero en cambio quiero tener esa otra cosa interesante, sin cambiar la forma del funtor. P.ej

import Data.Functor

42 <$ Just "boring"
--> Just 42

42 <$ Nothing
--> Nothing

"cool" <$ ["nonsense","stupid","uninteresting"]
--> ["cool","cool","cool"]

La definición es:

(<$) :: a -> f b -> f a
(<$) =  fmap . const

o escrito no como inútil:

cool <$ uncool =  fmap (const cool) uncool

Verá cómo constse usa aquí para "olvidarse" de la entrada.

Landei
fuente
21

Parece que no puedo encontrar nada relevante con respecto a esta función.

Muchas de las otras respuestas discuten aplicaciones relativamente esotéricas (al menos para los recién llegados) de const. Aquí hay uno simple: puede usar constpara deshacerse de un lambda que toma dos argumentos, desecha el primero pero hace algo interesante con el segundo.

Por ejemplo, la siguiente implementación (ineficiente pero instructiva) de length,

length' = foldr (\_ acc -> 1 + acc) 0

se puede reescribir como

length' = foldr (const (1+)) 0

que es quizás más elegante.

De const (1+)hecho, la expresión es semánticamente equivalente a \_ acc -> 1 + acc, porque toma un argumento, lo descarta y devuelve la sección (1+) .

jub0bs
fuente
4
Me tomó 5 minutos entender cómo funciona esto :)
Mukesh Soni
15

Otro uso es implementar funciones miembro de clase que tienen un argumento ficticio que no debe evaluarse (utilizado para resolver tipos ambiguos). Ejemplo que podría estar en Data.bits:

instance Bits Int where
  isSigned = const True
  bitSize  = const wordSize
  ...

Al usar const, decimos explícitamente que estamos definiendo valores constantes.

Personalmente, no me gusta el uso de parámetros ficticios, pero si se usan en una clase, esta es una forma bastante agradable de escribir instancias.

Jonas Duregård
fuente
Los argumentos de proxy son mucho mejores, y cuando apuntan a GHC recientes, las aplicaciones de tipo funcionan perfectamente.
dfeuer
2

constpuede ser solo la implementación que busca junto con otras funciones. Aquí hay un ejemplo que descubrí.

Digamos que queremos reescribir una estructura de 2 tuplas en otra estructura de 2 tuplas. Podría expresar esto así:

((a,b),(c,d))  (a,(c,(5,a)))

Puedo dar una definición sencilla con la coincidencia de patrones:

f ((a,b),(c,d)) = (a,(c,(5,a)))

¿Qué pasa si quiero una solución inútil (tácita) para este tipo de reescrituras? Un poco de pensamiento y jugueteo más tarde, la respuesta es que podemos expresar cualquier reescritura con (&&&), const, (.), fst, snd. Tenga en cuenta que (&&&)es de Control.Arrow.

La solución del ejemplo usando estas funciones es:

(fst.fst &&& (fst.snd &&& (const 5 &&& fst.fst)))

Tenga en cuenta la similitud con (a,(c,(5,a))). ¿Y si reemplazamos &&&con ,? Luego dice:

(fst.fst, (fst.snd, (const 5, fst.fst)))

Observa cómo aes el primer elemento del primer elemento, y eso es lo que fst.fstproyecta. Observe cómo ces el primer elemento del segundo elemento, y eso es lo que fst.sndproyecta. Es decir, las variables se convierten en el camino hacia su fuente.

constnos permite introducir constantes. ¡Es interesante cómo el nombre se alinea con el significado!

Entonces generalizó esta idea con Aplicativo para que pueda escribir cualquier función en un estilo sin sentido (siempre y cuando tenga el análisis de casos disponibles como funciones, como por ejemplo maybe, either, bool). Nuevamente, constjuega el papel de introducir constantes. Puede ver este trabajo en el paquete Data.Function.Tacit .

Cuando comienzas de manera abstracta, en la meta, y luego trabajas hacia una implementación, puedes sorprenderte con las respuestas. Es decir, cualquier función puede ser tan misteriosa como cualquier engranaje de una máquina. Sin embargo, si retrocede para ver toda la máquina, puede comprender el contexto en el que ese engranaje es necesario.

erisco
fuente
2

Supongamos que desea crear una lista de Nothingsigual a la longitud de una cadena. Como constdevuelve su primer argumento, no importa el segundo, puede hacer:

listOfNothings :: String -> [Maybe Char]
listOfNothings = (map . const) Nothing

o, más explícitamente:

listOfNothing st = map (const Nothing) st
A.Saramet
fuente
0

Digamos que desea rotar una lista. Esta es una forma idiomática de hacerlo en Haskell:

rotate :: Int -> [a] -> [a] rotate _ [] = [] rotate n xs = zipWith const (drop n (cycle xs)) xs

Esta función comprime dos matrices con la función const, la primera es una matriz cíclica infinita, la segunda es la matriz con la que comenzó.

const actúa como verificación de límites y utiliza la matriz original para terminar la matriz cíclica.

Ver: Rotar una lista en Haskell

Jameis famosos
fuente
0

Parece que no puedo encontrar nada relevante con respecto a esta función.

Suponga que le gustaría generar todas las subsecuencias de una lista dada.

Para cada elemento de la lista, en un punto dado, puede elegir entre Verdadero (incluirlo en la subsecuencia actual) o Falso (no incluirlo). Esto se puede hacer usando la función filterM .

Me gusta esto:

 λ> import Control.Monad
 λ> :t filterM
 filterM :: Applicative m => (a -> m Bool) -> [a] -> m [a]
 λ> 

Por ejemplo, queremos todas las subsecuencias de [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],[]]
 λ> 
jpmarinier
fuente