Pregunta ¿Cuál es el punto de 'const' en el preludio de Haskell?


Mirando a través del preludio de Haskell, ver 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 se puede usar esta función?


75
2017-09-13 13:17


origen


Respuestas:


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

x >> y = x >>= const y

Es algo más limpio que usar una lambda

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

e incluso puedes usarlo sin puntos

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

aunque no lo recomiendo especialmente en este caso.


70
2017-09-13 13:20



Para agregar a la excelente respuesta directa de hammar: funciones humildes como const y id son realmente útiles como una función de orden superior por la misma razón que son fundamental en el SKI combinator calculus.

No es que crea 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.

Un plug desvergonzado, pero publiqué sobre cómo la instancia Applicative para (->) son en realidad el S y K combinadores aquí, si ese es el tipo de cosa que te gusta.


24
2017-09-13 14:40



Un simple ejemplo 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 escrito no como sin sentido:

cool <$ uncool =  fmap (const cool) uncool

Ya ves cómo const se usa aquí para "olvidar" acerca de la entrada.


21
2017-09-14 08:30



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 el recién llegado) de const. Aquí hay uno simple: puedes usar const deshacerse de una lambda que toma dos argumentos, descarta la primera pero hace algo interesante con la segunda.

Por ejemplo, la siguiente implementación (ineficaz) de length,

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

puede ser reescrito como

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

que es quizás más elegante.

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


14
2018-02-12 20:49



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
  ...

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.


12
2017-09-14 09:25



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. Debo expresar esto así:

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

Puedo dar una definición directa 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? Al pensar y tocar más tarde, la respuesta es que podemos expresar cualquier reescritura con (&&&), const, (.), fst, snd. Tenga en cuenta que (&&&) es desde Control.Arrow.

La solución del ejemplo que usa estas funciones es:

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

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

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

Date cuenta cómo a es el primer elemento del primer elemento, y eso es lo fst.fst proyectos. Date cuenta cómo c es el primer elemento del segundo elemento, y eso es lo fst.snd proyectos. 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!

Luego generalicé esta idea con Applicative para que pueda escribir cualquier función en un estilo sin sentido (siempre que tenga análisis de casos disponibles como funciones, como maybe, either, bool) De nuevo, const juega el papel de introducir constantes. Puedes ver este trabajo en el Data.Function.Tacit paquete.

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 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.


2
2018-06-13 19:21