2010-06-20 9 views
9

Come si estrae un valore da una variabile di un costruttore sconosciuto?Corrispondenza modello in un'espressione let

Per esempio, vorrei negare il valore in entrambi i casi, se è stato costruito come un diritto:

let Right x = getValue 
in Right (negate x)

Questo codice si lega con successo il valore di destra (un int in questo caso) a x.

Funziona, ma cosa succede se getValue restituisce una sinistra invece? C'è un modo per determinare il tipo di una variabile in un'espressione let? O c'è un modo migliore per affrontare questo problema?

risposta

17

In generale, ciò che si può fare è questo:

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

Quello che fa dovrebbe essere chiaro: è proprio come il pattern matching in un argomento di funzione, ma contro un valore. Per fare ciò che ti serve, hai un caso predefinito che cattura tutto ciò che non corrisponde, e poi restituiscilo.

Nel tuo caso particolare, però, si può fare qualcosa di leggermente più bello:

negate `fmap` getValue 

Oppure, con import Control.Applicative, è possibile utilizzare <$> come sinonimo di fmap (negate <$> getValue). La funzione fmap ha il tipo fmap :: Functor f => (a -> b) -> f a -> f b. Per qualsiasi functor , fmap converte una funzione su valori ordinari in una funzione all'interno del functor. Ad esempio, gli elenchi sono un funtore e per gli elenchi, fmap = map. Qui, Either e rappresenta un functor che è un'eccezione Left e o un valore Right a; l'applicazione di una funzione a Left non esegue nulla, ma l'applicazione di una funzione a Right lo applica all'interno dello Right. In altre parole,

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

Così la versione case è la risposta diretta alla sua domanda, ma il tuo esempio particolare è più ben approssimata da fmap.

1: In una prima approssimazione, i funtori sono "contenitori". Se non ti senti a tuo agio con le varie classi di tipi, mi raccomando the Typeclassopedia per un riferimento completo; ci sono molti altri tutorial là fuori, e il modo migliore per farti un'idea è semplicemente giocare con loro. Tuttavia, il fmap per tipi specifici è spesso facilmente utilizzabile (soprattutto, secondo me, quando viene scritto <$>).

+4

e non dimenticare bello 'o sinistra (a destra negare.) GetValue' da' Data.Either';) – ony

+0

Grazie. L'espressione del caso è ciò che stavo cercando. Non capisco il resto della tua risposta; Tornerò su di esso una volta che ho imparato di più. – titaniumdecoy

+0

@ony: Penso che dovresti scrivere il tuo commento come una risposta separata, è davvero la soluzione di livello intermedio tra 'case' e' fmap'! – yatima2975

2

risposta al titolo di questa interrogazione:
non vedo grande differenza tra "... where" e "let ... in ...". Entrambi permette di fare dichiarare diversi casi di attacchi funzione argomento:

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

Problemi correlati