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