2012-01-26 14 views

risposta

18

Questa è l'istanza per ((->) r), funzioni da un tipo comune. Combina funzioni con lo stesso tipo di primo argomento in un'unica funzione duplicando un singolo argomento da utilizzare per tutte. (<$>) è la composizione di funzione, pura è const, ed ecco cosa (<*>) si traduce in:

s :: (r -> a -> b) -> (r -> a) -> r -> b 
s f g x = f x (g x) 

Questa funzione è forse meglio conosciuto come the S combinator.

Il ((->) r) funtore è anche il Reader Monade, dove l'argomento condiviso è il valore "ambiente", per esempio:

newtype Reader r a = Reader (r -> a) 

io non direi che è comune di fare questo per il gusto di fare funziona senza punti, ma in alcuni casi può effettivamente migliorare la chiarezza una volta che sei abituato all'idioma. L'esempio che hai dato, ad esempio, posso leggere molto facilmente nel senso che "è un carattere una lettera o un numero".

+0

s f g x = s x (g x) dovrebbe essere s f g x = f x (g x) – hvintus

+0

@hvintus: Whoops, typo. Grazie! –

7

Si ottengono istanze di quelle che vengono chiamate frecce statiche (vedere "Programmazione applicativa con effetti" di Conor McBride et al.) Gratuitamente dal pacchetto Control.Applicative. Pertanto, qualsiasi tipo di origine, nel tuo caso Char, genera un'istanza Applicativa in cui qualsiasi altro tipo a viene associato al tipo Char -> a.

Quando si combinano uno di questi, dicono applicare una funzione f :: Char -> a -> b ad un valore x :: Char -> a, la semantica è che si crea una nuova funzione Char -> b, che andranno ad alimentare il suo argomento in entrambi f e x in questo modo,

f <*> x = \c -> (f c) (x c) 

Quindi, come fai notare, questo rende il vostro esempio, equivale a

isAlphaNum c = (isAlpha c) || (isNum c) 

a mio parere, tale sforzo non è sempre necessario, e sarebbe aspetto molto più gradevole se Haskell avesse un supporto sintattico migliore per gli applicativi (forse qualcosa come i linguaggi a 2 livelli).

3

Si noti che si ottiene un effetto simile utilizzando le funzioni di sollevamento, ad es.:

import Data.Char 
import Control.Applicative 

isAlphaNum = liftA2 (||) isAlpha isNumber 

Oppure, utilizzando l'istanza monade ((->) r) al posto del applicativa uno:

import Data.Char 
import Control.Monad 

isAlphaNum = liftM2 (||) isAlpha isNumber 

[Digressione]

Ora che sapete come distribuire un argomento a due funzioni intermedie e il risultato a una funzione binaria, c'è il caso in qualche modo correlato che si desidera distribuire ute due argomenti uno funzione intermedia ei risultati di una funzione binaria:

import Data.Function 

orFst = (||) `on` fst 

-- orFst (True,3) (False, 7) 
--> True 

Questo modello è es spesso utilizzato per la funzione compare.

+2

C'è anche 'Control.Concatenative' che porta in Haskell alcuni combinatori concatenativi standard. I tuoi esempi potrebbero anche essere 'bi isAlpha isNumber (||)' e 'fst \' biAp \ '(||)'. Non è necessariamente mostrato qui, ma "Control.Concatenative" aiuta a migliorare la leggibilità per molte espressioni point-free, perché, beh, questo è ciò che riguarda la programmazione concatenativa. –

+0

Grazie, devo dare un'occhiata a questo modulo ... – Landei

Problemi correlati