2011-09-13 13 views
73

Mirando a través del Preludio Haskell, que see a functionconst:¿Cuál es el punto de 'const' en el preludio Haskell?

const x _ = x 

Me parece que no puede encontrar nada relevante con respecto a esta función.

¿Cuál es el punto? ¿Alguien puede dar un ejemplo de dónde se puede usar esta función?

+5

Un ejemplo: 'backgroundColor :: Texto -> Color' es para mí' backgroundColor = const White' – Zhen

Respuesta

68

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

x >> y = x >>= const y 

Es un poco más limpio que el uso de un lambda

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

e incluso se puede utilizar sea punto de libre

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

aunque no lo recomiendo particularmente en este caso.

+8

1. También aparece con frecuencia cuando se usan combinadores de analizador. –

+37

Ahh por lo que es más un 'generador de funciones' - lo uso con un argumento, y me da una función (teniendo un argumento) que siempre devuelve un valor constante. Entonces 'map (const 42) [1..5]' da como resultado '[42, 42, 42, 42, 42]'. – stusmith

+2

stusmith: Lo tienes. 'const' es útil para aplicar a un único argumento para producir una función donde se necesita (como pasar a' map'). – Conal

24

Para añadir a la excelente respuesta directa de Hammar: funciones humilde como const y id son muy útiles como una función de orden superior por la misma razón que son fundamentales en el SKI combinator calculus.

No es que creo que las funciones de preludio de Haskell fueron modeladas conscientemente después de ese sistema formal o algo así. Es solo que crear abstracciones ricas en haskell es muy fácil, por lo que a menudo se ve que este tipo de cosas teóricas emergen como prácticamente útiles.

Enchufe desvergonzado, pero en su blog acerca de cómo la instancia Aplicativo para (->) son en realidad los S y K combinadores here, si ese es el tipo de cosas que te gusta.

+7

Bueno, los combinadores SKI sin duda influyó en el preludio. Recuerdo haber discutido con Joe Fasel si el combinador S debería incluirse o no. – augustss

+4

Por cierto, '((->) e)' también es la mónada lector - con 'Reader' y similares sólo ser' envoltorios newtype' - y el 'ask' función es entonces' id', por lo que es el ' I' combinator también. Si nos fijamos en su lugar a base de Haskell Curry originales BCKW, 'B', 'K', y' 'W' son fmap',' return', y 'join' respectivamente. –

+1

El enlace del blog en la respuesta está muerto. Ahora debería señalar aquí: http://brandon.si/code/do-applicative-functors-generalize-the-s-k-combinators/ – nsxt

19

Un ejemplo simple para usar const es Data.Functor.(<$). Con esta función puedes decir: tengo aquí un functor con algo aburrido, pero en su lugar quiero tener esa otra cosa interesante en él, 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 escrita no es tan insustancial:

cool <$ uncool = fmap (const cool) uncool 

Ves como se utiliza aquí para const "olvidarse" de la entrada.

11

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

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

Mediante el uso de const nos dice 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.

13

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

Muchas de las otras respuestas discuten aplicaciones relativamente esotéricas (al menos para el recién llegado) de const. Aquí hay uno simple: puede usar const para deshacerse de una lambda que toma dos argumentos, descarta la primera pero hace algo interesante con la segunda.

Por ejemplo, la siguiente aplicación (ineficiente!) De length,

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

puede reescribirse como

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

que es quizás más elegante.

La expresión const (1+) es de hecho equivalente a \_ acc -> 1 + acc, porque toma un argumento, lo tira, y devuelve la sección (1+).

+2

Me tomó 5 minutos para entender cómo funciona esto :) –

1

const puede ser solo la implementación que está buscando junto con otras funciones. Aquí hay un ejemplo que descubrí.

Digamos que queremos reescribir una estructura de 2-tuplas a otra estructura de 2-tuplas. Yo podría expresar esto como tan:

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

me puede dar una definición recta hacia adelante con la coincidencia de modelos:

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

¿Y si quiero una solución inútil (tácito) para este tipo de reescrituras? Al pensar y manipular 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))) 

Nota la similitud con (a,(c,(5,a))). ¿Qué pasa si reemplazamos &&& con ,? A continuación, se lee:

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

Observe cómo a es el primer elemento del primer elemento, y eso es lo fst.fst proyectos. Observe cómo c es el primer elemento del segundo elemento, y eso es lo que proyecta fst.snd. Es decir, las variables se convierten en el camino hacia su origen.

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

entonces generalizar 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, tales como maybe, either, bool). Nuevamente, const juega el rol de introducir constantes. Puede ver este trabajo en el paquete Data.Function.Tacit.

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