Domanda

Qualche tempo fa, ho chiesto a domanda su $ e ho ottenuto risposte utili - in effetti, ho pensato di aver capito come usarlo.

Sembra che mi sia sbagliato :(

Questo esempio viene mostrato in un tutorial:

instance Monad [] where
   xs >>= f = concat . map f $ xs

Non posso per la vita di me vedere perché $ è stato usato lì; ghci non mi sta aiutando, dato che anche i test che faccio lì sembrano mostrare equivalenza con la versione che semplicemente ometterebbe $. Qualcuno può chiarire questo per me?

È stato utile?

Soluzione

Il $ viene utilizzato qui perché ha una precedenza inferiore rispetto alla normale applicazione delle funzioni. Un altro modo di scrivere questo codice è così:

instance Monad [] where
   xs >>= f = (concat . map f) xs

L'idea qui è di costruire prima una funzione ( concat. map f ) e quindi applicarla al suo argomento ( xs ). Come mostrato, questo può essere fatto anche semplicemente mettendo la parentesi attorno alla prima parte.

Nota che non è possibile omettere $ nella definizione originale, si verificherà un errore di tipo. Questo perché l'operatore di composizione della funzione (. ) ha una precedenza inferiore rispetto alla normale applicazione di funzione che trasforma effettivamente l'espressione in:

instance Monad [] where
  xs >>= f = concat . (map f xs)

Il che non ha senso, perché il secondo argomento per l'operatore di composizione della funzione non è affatto una funzione. Sebbene la seguente definizione abbia un senso:

instance Monad [] where
  xs >>= f = concat (map f xs)

Per inciso, questa è anche la definizione che preferirei, perché mi sembra molto più chiara.

Altri suggerimenti

Vorrei spiegare perché IMHO non è qui lo stile usato:

instance Monad [] where
  xs >>= f = concat (map f xs)

concat. map f è un esempio della cosiddetta scrittura in stile pointfree; dove pointfree significa "senza il punto di applicazione". Ricorda che in matematica, nell'espressione y = f (x) , diciamo che f è applicato sul punto x . Nella maggior parte dei casi, puoi effettivamente eseguire un passaggio finale, sostituendo:

f x = something $ x

con

f = something

come f = concat. map f , e questo è in realtà uno stile inutile. Ciò che è più chiaro è discutibile, ma lo stile privo di punti fornisce un diverso punto di vista che è anche utile, quindi a volte viene utilizzato anche quando non è esattamente necessario.

EDIT: ho sostituito inutile con inutile e risolto alcuni esempi, dopo il commento di Alasdair, che dovrei ringraziare.

Il motivo per cui $ viene usato qui è dovuto alla firma del tipo di (.):

(.) :: (b -> c) -> (a -> c) -> a -> c

Qui abbiamo

map f :: [a] -> [[b]]

e

concat :: [[b]] -> [b]

Quindi finiamo con

concat . map f :: [a] -> [b]

e il tipo di (.) potrebbero essere scritti come

(.) :: ([[b]] ??- > [b]) - > ([a] - > [[b]]) - > [a] - > [B]

Se dovessimo usare concat. map f xs , lo vedremmo

map f xs :: [[b]]

E quindi non può essere usato con (.). (il tipo dovrebbe essere (.) :: (a - > b) - > a - > b

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top