Domanda

Qual è la differenza tra il dot (.) e il segno del dollaro ($)?

Da quanto ho capito, sono entrambi zucchero sintattico per non dover usare le parentesi.

È stato utile?

Soluzione

L'operatore $ è per evitare parentesi. Tutto ciò che appare dopo che avrà la precedenza su tutto ciò che viene prima.

Per esempio, diciamo che hai una linea che legge:

putStrLn (show (1 + 1))

Se si vuole sbarazzarsi di quelle parentesi, una delle seguenti linee sarebbe anche fare la stessa cosa:

putStrLn (show $ 1 + 1)
putStrLn $ show (1 + 1)
putStrLn $ show $ 1 + 1

Lo scopo principale del gestore . non è evitare parentesi, ma a funzioni catena. Esso consente di legare l'output di ciò che appare sulla destra con l'ingresso di qualsiasi appare sulla sinistra. Ciò si traduce di solito anche in un minor numero tra parentesi, ma funziona in modo diverso.

Tornando lo stesso esempio:

putStrLn (show (1 + 1))
  1. (1 + 1) non ha un ingresso, e pertanto non può essere utilizzato con l'operatore ..
  2. show può prendere un Int e restituire una String.
  3. putStrLn può prendere un String e restituire un IO ().

È possibile catena show a putStrLn in questo modo:

(putStrLn . show) (1 + 1)

Se questo è troppe parentesi per i vostri gusti, sbarazzarsi di loro con l'operatore $:

putStrLn . show $ 1 + 1

Altri suggerimenti

Ci sono diversi tipi e le diverse definizioni:

infixr 9 .
(.) :: (b -> c) -> (a -> b) -> (a -> c)
(f . g) x = f (g x)

infixr 0 $
($) :: (a -> b) -> a -> b
f $ x = f x

($) intende sostituire normale applicazione funzione ma ad una precedenza differente per aiutare ad evitare parentesi. (.) è per comporre due funzioni insieme per fare una nuova funzione.

In alcuni casi essi sono intercambiabili, ma questo non è vero in generale. L'esempio tipico dove si trovano è:

f $ g $ h $ x

==>

f . g . h $ x

In altre parole una catena di $s, tutti tranne quello finale può essere sostituita da .

Anche notare che ($) è la funzione di identità specializzati per tipi di funzione.L'identità funzione simile a questo:

id :: a -> a
id x = x

Mentre ($) assomiglia a questo:

($) :: (a -> b) -> (a -> b)
($) = id

Notare che ho volutamente aggiunto extra parentesi il tipo di firma.

Gli usi di ($) di solito può essere risolto aggiungendo una parentesi (a meno che l'operatore è utilizzato in una sezione).E. g.: f $ g x diventa f (g x).

Gli usi di (.) sono spesso un po ' più difficile da sostituire;di solito hanno bisogno di un lambda o l'introduzione di un esplicito parametro di funzione.Per esempio:

f = g . h

diventa

f x = (g . h) x

diventa

f x = g (h x)

Spero che questo aiuta!

($) permette funzioni di essere collegati senza aggiungere parentesi per controllare l'ordine di valutazione:

Prelude> head (tail "asdf")
's'

Prelude> head $ tail "asdf"
's'

Il (.) operatore composizione crea una nuova funzione senza specificare gli argomenti:

Prelude> let second x = head $ tail x
Prelude> second "asdf"
's'

Prelude> let second = head . tail
Prelude> second "asdf"
's'

L'esempio precedente è probabilmente illustrativo, ma non mostra realmente la comodità di utilizzo composizione. Ecco un'altra analogia:

Prelude> let third x = head $ tail $ tail x
Prelude> map third ["asdf", "qwer", "1234"]
"de3"

Se usiamo solo terza volta, siamo in grado di evitare di nominare esso utilizzando un lambda:

Prelude> map (\x -> head $ tail $ tail x) ["asdf", "qwer", "1234"]
"de3"

Infine, la composizione ci permette di evitare la lambda:

Prelude> map (head . tail . tail) ["asdf", "qwer", "1234"]
"de3"

La versione breve e dolce:

  • ($) chiama la funzione, che è il suo argomento a sinistra sul valore che è il suo argomento a destra.
  • (.) compone la funzione, che è il suo argomento a sinistra sulla funzione che è il suo argomento a destra.

Un'applicazione che è utile e mi ha portato un po 'di tempo per capire dalla breve descrizione a voi imparare una Haskell : dal:

f $ x = f x

e mettere tra parentesi destra di un'espressione contenente un operatore infisso converte in una funzione prefisso, si può scrivere ($ 3) (4+) analogo a (++", world") "hello".

Perché qualcuno dovrebbe fare questo? Per gli elenchi delle funzioni, per esempio. Entrambi:

map (++", world") ["hello","goodbye"]`

e

map ($ 3) [(4+),(3*)]

sono più breve di map (\x -> x ++ ", world") ... o map (\f -> f 3) .... Ovviamente, queste ultime varianti sarebbero più leggibile per la maggior parte delle persone.

... o si potrebbe evitare le costruzioni . e $ utilizzando pipelining :

third xs = xs |> tail |> tail |> head

Ecco, dopo aver aggiunto la funzione di supporto:

(|>) x y = y x

Un ottimo modo per saperne di più su qualsiasi cosa (qualsiasi funzione) è quello di ricordare che tutto è una funzione! Questo mantra generale aiuta, ma in casi specifici come gli operatori, aiuta a ricordare questo piccolo trucco:

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

e

:t ($)
($) :: (a -> b) -> a -> b

Basta ricordarsi di utilizzare :t liberalmente, e avvolgere i vostri operatori in ()!

La mia regola è semplice (sono principianti troppo):

  • non utilizzare . se si vuole passare il parametro (chiamare la funzione), e
  • Non utilizzare $ se non v'è ancora alcun parametro (comporre una funzione)

Questo è il

show $ head [1, 2]

ma mai:

show . head [1, 2]
  

Haskell: differenza tra . (punto) e $ (simbolo del dollaro)

     

Qual è la differenza tra il punto (.) e il simbolo del dollaro ($) ?. Se ho capito bene, sono entrambi zucchero sintattico per non dover usare le parentesi.

Sono non zucchero sintattico per non dover utilizzare le parentesi - sono funzioni, - infissa, così possiamo chiamarli operatori.

Componi, (.), e quando usarlo.

(.) è la funzione di composizione. Quindi

result = (f . g) x

è la stessa come la costruzione di una funzione che passa il risultato del suo argomento passato a g a f.

h = \x -> f (g x)
result = h x

Usa (.) quando non si hanno gli argomenti disponibili per passare alle funzioni che si desidera comporre.

associativa Destra applicare, ($), e quando usarlo

($) è un diritto-associativa funzione di applicare con precedenza bassa vincolante. Così si limita a calcolare le cose a destra della prima. Così,

result = f $ g x

è lo stesso di questo, procedurale (che conta dal Haskell viene valutata pigramente, inizierà a valutare f prima):

h = f
g_x = g x
result = h g_x

o più conciso:

result = f (g x)

Utilizzare ($) quando si dispone di tutte le variabili per valutare prima di applicare la funzione precedente per il risultato.

Possiamo vedere questo leggendo la fonte per ogni funzione.

Leggi Source

Ecco il fonte per (.):

-- | Function composition.
{-# INLINE (.) #-}
-- Make sure it has TWO args only on the left, so that it inlines
-- when applied to two functions, even if there is no final argument
(.)    :: (b -> c) -> (a -> b) -> a -> c
(.) f g = \x -> f (g x)

Ed ecco la fonte per ($):

-- | Application operator.  This operator is redundant, since ordinary
-- application @(f x)@ means the same as @(f '$' x)@. However, '$' has
-- low, right-associative binding precedence, so it sometimes allows
-- parentheses to be omitted; for example:
--
-- >     f $ g $ h x  =  f (g (h x))
--
-- It is also useful in higher-order situations, such as @'map' ('$' 0) xs@,
-- or @'Data.List.zipWith' ('$') fs xs@.
{-# INLINE ($) #-}
($)                     :: (a -> b) -> a -> b
f $ x                   =  f x

Conclusione

Usa composizione quando non necessario valutare immediatamente la funzione. Forse si vuole passare alla funzione che deriva dalla composizione a un'altra funzione.

Usa applicazione quando si stanno fornendo tutti gli argomenti per una valutazione completa.

Così, per il nostro esempio, sarebbe semanticamente preferibile fare

f $ g x

quando abbiamo x (o meglio, le argomentazioni di g), e facciamo:

f . g

quando non lo facciamo.

Credo che un breve esempio di dove si usa e non . $ aiuterebbe a chiarire le cose.

double x = x * 2
triple x = x * 3
times6 = double . triple

:i times6
times6 :: Num c => c -> c

Si noti che times6 è una funzione che viene creato dalla composizione funzione.

Tutte le altre risposte sono piuttosto buone. Ma c'è un dettaglio importante usabilità circa come tratta ghc $, che il tipo di controllo GHC consente instatiarion con rango più elevato tipi / quantificati. Se si guarda al tipo di $ id per esempio troverete che ci vorrà una funzione il cui argomento è di per sé una funzione polimorfica. Piccole cose che non hanno la stessa flessibilità con un operatore sconvolto equivalente. (Questo rende in realtà mi chiedo se $! Merita lo stesso trattamento o no)

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