yourself you monad learn data haskell applicative

data - monads learn you a haskell



¿Para qué son útiles algunos "algunos" y "muchos" de Alternative? (4)

Alternative , una extensión de Applicative , declara empty , <|> y estas dos funciones:

Uno o mas:

some :: f a -> f [a]

Cero o más:

many :: f a -> f [a]

Si se define, some y many deberían ser las soluciones mínimas de las ecuaciones:

some v = (:) <$> v <*> many v many v = some v <|> pure []

No pude encontrar una instancia para la cual some y many están definidos. ¿Cuál es su significado y uso práctico? ¿Se usan para nada? No he podido entender su propósito solo desde esta definición.

Actualización: No estoy preguntando qué es Alternative , solo cuáles son some y many


En el solicitante STM, some significarían: seguir intentando hasta que tenga éxito al menos una vez, y luego seguir haciéndolo hasta que falle. many querrían decir: haz esto tantas veces como puedas hasta el fracaso.


Tiendo a verlos en las bibliotecas Applicative Component Cominator.

a :: Parser [String] a = some (string "hello")

y veo many utilizados para el propósito en las definiciones predeterminadas de Parsing en parsers .

Creo que Parsec es el ejemplo principal de una biblioteca de combinaciones de analizadores que oculta el uso de some / many ya que redefine cosas como (<|>) .


Una instancia de ejemplo elemental: con

import Control.Monad(Functor(..)) import Control.Applicative import Data.Char -- char string parser newtype P a = P { runP :: String -> [(a,String)] } -- runP (P p) s = p s instance Functor P where -- fmap :: (a -> b) -> f a -> f b fmap f (P q) = P (/s -> [ (f y,ys) | (y,ys) <- q s]) instance Applicative P where -- pure :: a -> f a pure x = P (/s -> [(x,s)]) -- (<*>) :: f (a -> b) -> f a -> f b P p <*> P q = P (/s -> [(x y, ys) | (x,xs) <- p s, (y,ys) <- q xs]) letter = P p where -- sample parser p (x:xs) | isAlpha x = [(x,xs)] p _ = []

tenemos

*Main Data.Char> runP letter "123" [] *Main Data.Char> runP letter "a123" [(''a'',"123")] *Main Data.Char> runP ( (:) <$> letter <*> pure []) "a123" [("a","123")] *Main Data.Char> runP ( (:) <$> letter <*> ((:)<$>letter <*> pure []) ) "a123" [] *Main Data.Char> runP ( (:) <$> letter <*> ((:)<$>letter <*> pure []) ) "ab123" [("ab","123")] -- NOT NICE ^^^^^^^^^^^^^^^^^^^^ -}

Entonces, con

instance Alternative P where -- (<|>) :: f a -> f a -> f a P p <|> P q = P (/s-> p s ++ q s) -- empty :: f a -- the identity of <|> empty = P (/s-> [])

obtenemos

*Main Data.Char> runP (many letter) "ab123" [("ab","123"),("a","b123"),("","ab123")] *Main Data.Char> runP (some letter) "ab123" [("ab","123"),("a","b123")] *Main Data.Char> runP (optional letter) "ab123" [(Just ''a'',"b123"),(Nothing,"ab123")] *Main Data.Char> runP (optional letter) "123" [(Nothing,"123")] Prelude Main Data.Traversable> runP (sequenceA $ replicate 2 letter) "ab123" [("ab","123")] -- NICE ^^^^^^^^^^^^^^^^^^^ -}


Will proporcionó un buen ejemplo motivando el uso de esos métodos, pero parece que todavía tiene un malentendido acerca de las clases de tipos.

Una definición de clase de tipo enumera las firmas de tipo para los métodos que existen para todas las instancias de la clase de tipo. También puede proporcionar implementaciones predeterminadas de esos métodos, que es lo que está sucediendo con algunos y muchos métodos de Alternative.

Para que sean instancias válidas, todos los métodos deben definirse para la instancia. Por lo tanto, los que descubrió que no definieron instancias específicas para algunos o muchos usaron las implementaciones predeterminadas , y el código para ellos es exactamente el que figura en su pregunta.

Entonces, para ser claros, algunos y muchos de hecho están definidos y se pueden usar con todas las instancias alternativas gracias a las definiciones predeterminadas dadas con la definición de clase de tipo.