ventajas usos tuplas reservadas peta para palabras librerias importar funciones español entornos ejemplos desarrollo como haskell applicative

usos - ¿Qué hace el operador<|> de Haskell?



palabras reservadas haskell (4)

Revisar la documentación de Haskell siempre es un poco doloroso para mí, porque toda la información que obtienes sobre una función a menudo no es más que simplemente: fa -> f [a] que podría significar cualquier cantidad de cosas.

Como es el caso de la función <|> .

Todo lo que se me da es esto: (<|>) :: fa -> fa -> fa y que es una "operación binaria asociativa" ...

Tras la inspección de Control.Applicative , aprendo que aparentemente no está relacionado, dependiendo de la implementación.

instance Alternative Maybe where empty = Nothing Nothing <|> r = r l <|> _ = l

Ok, entonces vuelve a la derecha si no queda, de lo contrario vuelve a la izquierda, gotcha ... Esto me lleva a creer que es un operador "izquierdo o derecho", que tiene sentido dado su uso de | y | uso histórico de "O"

instance Alternative [] where empty = [] (<|>) = (++)

Excepto que aquí solo llama al operador de concatenación de la lista ... Rompiendo mi idea ...

Entonces, ¿qué es exactamente esa función? ¿De qué sirve? ¿Dónde encaja en el gran esquema de las cosas?


Estos parecen muy diferentes, pero considera:

Nothing <|> Nothing == Nothing [] <|> [] == [] Just a <|> Nothing == Just a [a] <|> [] == [a] Nothing <|> Just b == Just b [] <|> [b] == [b]

Entonces ... en realidad son muy, muy similares , incluso si la implementación se ve diferente. La única diferencia real es aquí:

Just a <|> Just b == Just a [a] <|> [b] == [a, b]

A Maybe solo puede contener un valor (o cero, pero no cualquier otra cantidad). Pero bueno, si ambos fueran idénticos , ¿por qué necesitarías dos tipos diferentes? El objetivo de que sean diferentes es, ya sabes, ser diferente .

En resumen, la implementación puede parecer totalmente diferente, pero en realidad son bastante similares.


Típicamente significa "elección" o "paralelo" en el sentido de que a <|> b es una "elección" de a o b a y b en paralelo. Pero retrocedamos.

Realmente, no hay un significado práctico para las operaciones en tipos de clases como (<*>) o (<|>) . Estas operaciones reciben significado de dos maneras: (1) a través de leyes y (2) a través de instancias. Si no estamos hablando de una instancia particular de Alternative entonces solo (1) está disponible para intuir el significado.

Así que "asociativo" significa que a <|> (b <|> c) es lo mismo que (a <|> b) <|> c . Esto es útil ya que significa que solo nos importa la secuencia de cosas encadenadas junto con (<|>) , no su "estructura de árbol".

Otras leyes incluyen identidad con empty . En particular, a <|> empty = empty <|> a = a . En nuestra intuición con "elección" o "paralelo" estas leyes se leen como "a o (algo imposible) debe ser un" o "a al costado (proceso vacío) es solo un". Indica que el empty es algún tipo de "modo de falla" para una Alternative .

Existen otras leyes sobre cómo (<|>) / empty interactúan con fmap (de Functor ) o pure / (<*>) (de Applicative ), pero quizás la mejor manera de avanzar en la comprensión del significado de (<|>) es examinar un ejemplo muy común de un tipo que ejemplifica Alternative : un Parser .

Si x :: Parser A y :: Parser B entonces (,) <$> x <*> y :: Parser (A, B) analiza x luego y en secuencia. Por el contrario, (fmap Left x) <|> (fmap Right y) analiza x o y , comenzando con x , para probar los dos posibles análisis. En otras palabras, indica una rama en su árbol de análisis sintáctico, una opción o un universo de análisis paralelo.


Un ejemplo interesante de una Alternative que no es un analizador o una cosa similar a MonadPlus es Concurrently , un tipo muy útil del paquete async .

Para Concurrently , el empty es un cálculo que continúa para siempre. Y (<|>) ejecuta sus argumentos al mismo tiempo, devuelve el resultado del primero que se completa y cancela el otro.


(<|>) :: fa -> fa -> fa realidad te dice bastante, incluso sin considerar las leyes de Alternative .

Toma dos valores de fa , y tiene que devolver uno. Por lo tanto, tendrá que combinar o seleccionar sus entradas de alguna manera. Es polimórfico en el tipo a , por lo que será completamente incapaz de inspeccionar los valores de tipo a puedan estar dentro de un fa ; esto significa que no puede hacer la "combinación" mediante la combinación de valores, por lo que debe ser puramente en términos de cualquier estructura que el constructor de tipo f añada.

El nombre ayuda un poco también. Algún tipo de "O" es de hecho el concepto vago que los autores intentaban indicar con el nombre "Alternativa" y el símbolo "<|>".

Ahora si tengo dos valores de Maybe a y tengo que combinarlos, ¿qué puedo hacer? Si ambos son Nothing , tendré que devolver Nothing , sin forma de crear un a . Si al menos uno de ellos es un Just ... puedo devolver una de mis entradas tal como están, o puedo devolver Nothing . Hay muy pocas funciones que incluso sean posibles con el tipo Maybe a -> Maybe a -> Maybe a , y para una clase cuyo nombre es "Alternativa" la dada es bastante razonable y obvia.

¿Qué hay de combinar dos valores [a] ? Aquí hay más funciones posibles, pero en realidad es bastante obvio lo que es probable que haga. Y el nombre "Alternativa" le da una buena pista de lo que probablemente será, siempre que esté familiarizado con la interpretación estándar de "no determinismo" de la lista de mónada / aplicativo; si ve un [a] como un "a no determinista" con una colección de valores posibles, entonces la forma obvia de "combinar dos valores no deterministas" de una manera que podría merecer el nombre "Alternativa" es producir un no determinístico que podría ser cualquiera de los valores de cualquiera de las entradas.

Y para los analizadores sintácticos; combinar dos analizadores tiene dos amplias interpretaciones obvias que vienen a la mente; ya sea que produzcas un analizador sintáctico que coincida con lo que hace el primero y luego lo hace el segundo, o si produces un analizador que concuerde con lo primero o lo segundo (hay por supuesto detalles sutiles de cada una de estas opciones que dejan espacio para opciones). Dado el nombre "Alternativa", la interpretación "o" parece muy natural para <|> .

Entonces, visto desde un nivel suficientemente alto de abstracción, estas operaciones hacen todo "hacer lo mismo". La clase de tipo es realmente para operar a ese alto nivel de abstracción donde todas estas cosas "se ven iguales". Cuando estoy operando en una sola instancia conocida, solo pienso en la operación <|> como exactamente lo que hace para ese tipo específico.