2010-06-20 13 views
9

¿Cómo se extrae un valor de una variable de un constructor desconocido?Coincidencia de patrones en una expresión let

Por ejemplo, me gustaría negar el valor en un Tanto si se construyó como un derecho:

let Right x = getValue 
in Right (negate x)

Este código se une con éxito el valor de la derecha (un Int en este caso) a x.

Esto funciona, pero ¿y si getValue devuelve una izquierda? ¿Hay alguna manera de determinar el tipo de variable en una expresión let? ¿O hay una mejor manera de abordar este problema?

Respuesta

17

En general, lo que puede hacer es lo siguiente:

case getValue of 
    Right x -> Right $ negate x 
    e  -> e 

Lo que esto hace que debe quedar claro: es igual que la coincidencia de patrones en un argumento de la función, pero en contra de un valor. Para hacer lo que necesita, tiene un caso predeterminado que atrapa todo lo que no coincida, y luego lo devuelve.

En su caso particular, sin embargo, se puede hacer algo un poco más bonitas:

negate `fmap` getValue 

O, con import Control.Applicative, puede utilizar <$> como sinónimo de fmap (negate <$> getValue). La función fmap tiene el tipo fmap :: Functor f => (a -> b) -> f a -> f b. Para cualquier functor , fmap convierte una función en valores ordinarios a una función dentro del funtor. Por ejemplo, las listas son un funtor, y para las listas, fmap = map. Aquí, Either e representa un functor que es una excepción Left e o un valor Right a; aplicar una función a Left no hace nada, pero aplicar una función a Right lo aplica dentro del Right. En otras palabras,

instance Functor (Either e) where 
    fmap _ (Left l) = Left l 
    fmap f (Right r) = Right $ f r 

lo tanto la versión case es la respuesta directa a su pregunta, pero su ejemplo particular es más bien aproximarse por fmap.

1: Para una primera aproximación, los funtores son "contenedores". Si no se siente cómodo con las diversas clases de tipo, recomiendo the Typeclassopedia para obtener una referencia completa; hay muchos más tutoriales, y la mejor forma de familiarizarse con ellos es simplemente jugar con ellos. Sin embargo, el fmap para tipos específicos a menudo es fácilmente utilizable (especialmente, en mi opinión, cuando se escribe <$>).

+4

y no se olvide agradable 'ya sea a la izquierda (derecha negar.) GetValue' de' Data.Either';) – ony

+0

Gracias. La expresión de caso es lo que estaba buscando. No entiendo el resto de tu respuesta; Volveré sobre eso una vez que haya aprendido más. – titaniumdecoy

+0

@ony: Creo que deberías escribir tu comentario como una respuesta separada, ¡es realmente la solución de nivel intermedio entre el 'case' y el' fmap'! – yatima2975

2

respuesta al título de esta pregunta:
no veo gran diferencia entre "... where" y "let ... in ...". Tanto le permite hacer declarar varios casos de consolidaciones argumento de la función:

f val = let negR (Right x) = Right (negate x) 
      negR y = y 
     in negR val 

o let { negR (Right x) = Right (negate x); negR y = y; } in negR val

Cuestiones relacionadas