2013-06-06 20 views
8

Sto provando a desugare una dichiarazione do in Haskell. Ho trovato alcuni esempi qui su SO ma non sono riuscito ad applicarli al mio caso. L'unica cosa a cui riesco a pensare è un'affermazione pesante e annidata, che sembra abbastanza brutta.Haskell do not bind

dichiarazione in cui fare la notazione dovrebbe essere sostituito da legare:

do num <- numberNode x 
    nt1 <- numberTree t1 
    nt2 <- numberTree t2 
    return (Node num nt1 nt2) 

Qualsiasi ingresso è molto apprezzato =)

risposta

11
numberNode x >>= \num -> 
    numberTree t1 >>= \nt1 -> 
    numberTree t2 >>= \nt2 -> 
     return (Node num nt1 nt2) 

Si noti che questo è più semplice se si utilizzano applicativi:

Node <$> numberNode x <*> numberTree t1 <*> numberTree t2 
+0

Grazie per aver spinto la mia testa contro questo muro. Non so perché, ma non ho proprio questa semplice soluzione. – floAr

+0

Prego! –

7

Questo è un caso d'uso eccellente per applicative style. È possibile sostituire l'intero frammento (dopo l'importazione Control.Applicative) con

Node <$> numberNode x <*> numberTree t1 <*> numberTree t2 

Pensate stile applicativo (utilizzando <$> e <*>) come applicazione di funzione di "lifting" in modo che funziona su functors pure. Se ignori mentalmente <$> e <*> sembra molto simile alla normale applicazione di funzione!

Lo stile applicativo è utile ogni volta che si ha una funzione pura e si desidera fornire argomenti impuri (o qualsiasi argomento di functor, in realtà) - in pratica quando si vuole fare ciò che si è specificato nella domanda!


La firma tipo di <$> è

(<$>) :: Functor f => (a -> b) -> f a -> f b 

che significa che richiede una funzione pura (in questo caso Node) e un valore funtore (in questo caso numberNode x) e crea una nuova funzione avvolto "dentro" un funtore. È possibile aggiungere ulteriori argomenti a questa funzione con <*>, che ha il tipo di firma

(<*>) :: Applicative f => f (a -> b) -> f a -> f b 

Come potete vedere, questo è molto simile a <$> solo funziona anche quando la funzione è avvolto "dentro" un funtore.

+0

Grazie per aver menzionato questo, non ho esperienza con gli applicativi ma il concetto sembra fantastico. È proprio questo tipo di modi bellissimi per risolvere i problemi che mi piacciono di Haskell :) Come stavo chiedendo all'operatore di binding accetterò la risposta di Gabriels, ma darò sicuramente un'occhiata più approfondita a questo concetto. Grazie mille per avermelo fatto notare =) – floAr

2

vorrei aggiungere ai post su applicativo di cui sopra ..

Considerando il tipo di <$>:

(<$>) :: Functor f => (a -> b) -> f a -> f b 

sembra proprio come FMAP:

fmap :: Functor f => (a -> b) -> f a -> f b 

che è anche molto simile a Control.Monad.liftM:

liftM :: Monad m => (a -> b) -> m a -> m b 

penso a questo come "Ho bisogno di sollevare il costruttore di dati in questo tipo"

In una nota correlata, se vi trovate a fare questo:

action >>= return . f 

voi invece di farlo:

f `fmap` action 

Il primo esempio utilizza l'associazione per prelevare il valore da qualsiasi tipo di azione è, chiamando f con esso, e quindi reimballando il risultato. Invece, possiamo sollevare f in modo che consideri il tipo di azione come argomento.

+0

Grazie per questa spiegazione continuativa =) – floAr

+1

'liftM3 :: Monad m => (a1 -> a2 -> a3 -> r) -> m a1 -> m a2 - > m a3 -> mr' o 'liftA3 :: Applicativo f => (a -> b -> c -> d) -> fa -> fb -> fc -> fd' sono disponibili importando' Control.Monad' o 'Control.Applicative', e sono più utili di semplici' fmap'/'liftM' qui. Ad esempio, 'liftA3 Node (numberNode x) (numberTree t1) (numberTree t2)' farebbe il trucco. – AndrewC

+0

Allo stato attuale, questo non risponde prontamente alla domanda. L'OP non può usarlo per risolvere il problema che hanno. Ecco perché hai bisogno di liftM3 o Applicative. – AndrewC