monad ejemplos haskell maybe

haskell - ejemplos - Plan B, o ¿qué es lo contrario de Maybe''s>>=?



maybe haskell ejemplos (2)

Tomemos dos funciones:

f :: a -> Maybe b g :: b -> Maybe c

La función >>= funcionaría de tal manera que f >>= g ejecutaría g con el resultado de f solo si no es Nothing . En otras palabras, se requiere que f y g tengan éxito para producir cualquier resultado.

Estoy implementando un analizador y me di cuenta de que mi lexer se beneficiaría de algo opuesto a esto. Es decir:

f :: a -> Maybe b g :: a -> Maybe b planb :: (a -> Maybe b) -> (a -> Maybe b) -> (a -> Maybe b) planb f g = /x -> case f x of Nothing -> g x res -> res

lo que significa probar f y si falla, intente g como un plan de respaldo. Con un lexer, significa tratar de hacer coincidir un tipo de token con la entrada actual y, si falla, tratar de hacer coincidir otro tipo de token (que finalmente se encadenaría para todos los tipos de token).

La búsqueda de Hoogle no dio como resultado ninguna de estas funciones, pero para mí, ¡esta función parece ser útil en muchos lugares!

Mi pregunta es, entonces, si ya existe una variante de planb que debería estar usando. Si no, ¿estoy haciendo algo extraordinario y hay una mejor manera de lograr lo que quiero?

PD: Pensé si tal función tiene sentido para Monad s en general, pero no tiene mucho sentido para mí fuera de Maybe y quizás de algunos otros.


La clase de tipos Alternative hace precisamente esto, es bastante similar a MonadPlus pero quizás un poco más general.

import Control.Applicative -- most general form planb :: (Applicative g, Alternative f) => g (f a) -> g (f a) -> g (f a) planb = liftA2 (<|>) -- specialized to (->) and Maybe planb'' :: (a -> Maybe b) -> (a -> Maybe b) -> (a -> Maybe b) planb'' = planb -- equivalent to planb'' (and planb) but without the fancy combinators planb'''' :: (a -> Maybe b) -> (a -> Maybe b) -> a -> Maybe b planb'''' f g x = f x <|> g x

Conectando esto a un caso de prueba simple:

test :: Maybe Int test = do a <- planb'' (const Nothing) id (Just 1) b <- planb'' id id (Just 1) c <- planb'' id (const Nothing) (Just 1) return $ a + b + c

Genera el resultado esperado:

*Main> test Just 3


Tenga en cuenta que su función planb solo necesita funcionar con valores Maybe ; llamar a las funciones para producirlas puede ser eliminado.

planb :: Maybe a -> Maybe a -> Maybe a planb Nothing b = b planb a _ = a

Y lo llamarías como planb (fx) (gx) para obtener un resultado de Maybe .

Con esto en mente, eche un vistazo a la clase MonadPlus (como lo sugiere Franky en un comentario):

planb = mplus

Es posible que también esté interesado en msum , que toma una lista de los valores de Maybe y devuelve el primero (si existe) que no es Nothing . Aquí hay una función práctica:

matchSomehow :: [a -> Maybe b] -> a -> Maybe b matchSomehow fs a = msum $ map ($a) fs