Jaka jest różnica między kropką (.)
a znakiem dolara ($)
?
Jak rozumiem, oba są cukrem syntaktycznym, ponieważ nie muszą używać nawiasów.
źródło
Jaka jest różnica między kropką (.)
a znakiem dolara ($)
?
Jak rozumiem, oba są cukrem syntaktycznym, ponieważ nie muszą używać nawiasów.
$
Operatora dla uniknięcia nawiasów. Wszystko, co pojawi się po nim, będzie miało pierwszeństwo przed wszystkim, co nastąpi wcześniej.
Załóżmy na przykład, że masz wiersz o treści:
putStrLn (show (1 + 1))
Jeśli chcesz się pozbyć tych nawiasów, dowolny z poniższych wierszy również zrobiłby to samo:
putStrLn (show $ 1 + 1)
putStrLn $ show (1 + 1)
putStrLn $ show $ 1 + 1
Głównym celem .
operatora nie jest unikanie nawiasów, ale połączenie funkcji. Pozwala powiązać wyjście tego, co pojawia się po prawej stronie, z wejściem tego, co pojawia się po lewej stronie. Powoduje to zwykle mniej nawiasów, ale działa inaczej.
Wracając do tego samego przykładu:
putStrLn (show (1 + 1))
(1 + 1)
nie ma danych wejściowych i dlatego nie można go używać z .
operatorem.show
może wziąć Int
i zwrócić a String
.putStrLn
może wziąć String
i zwrócić IO ()
.Możesz połączyć, show
aby putStrLn
polubić to:
(putStrLn . show) (1 + 1)
Jeśli jest to zbyt wiele nawiasów na twój gust, pozbądź się ich z $
operatorem:
putStrLn . show $ 1 + 1
putStrLn . show . (+1) $ 1
byłoby równoważne. Masz rację, ponieważ większość operatorów (wszystkie?) Są funkcjami.map ($3)
. Chodzi mi głównie o to,$
aby unikać nawiasów, ale to nie tak, że po to są.map ($3)
jest funkcją typuNum a => [(a->b)] -> [b]
. Pobiera listę funkcji z liczbą, stosuje 3 do wszystkich i zbiera wyniki.Mają różne typy i różne definicje:
($)
ma zastąpić normalną aplikację funkcji, ale ma inny priorytet, aby uniknąć nawiasów.(.)
służy do połączenia dwóch funkcji w celu utworzenia nowej funkcji.W niektórych przypadkach są one wymienne, ale ogólnie nie jest to prawdą. Typowy przykład, w którym się znajdują, to:
==>
Innymi słowy w łańcuchu
$
s, wszystkie oprócz ostatniego można zastąpić.
źródło
x
była funkcja? Czy możesz użyć go.
jako ostatecznego?x
w tym kontekście, to tak - ale wtedy „ostateczny” dotyczyłby czegoś innego niżx
. Jeśli nie aplikujeszx
, nie jest niczym innym jakx
byciem wartością.Zauważ też, że
($)
jest to funkcja tożsamości wyspecjalizowana w typach funkcji . Funkcja tożsamości wygląda następująco:Chociaż
($)
wygląda tak:Zauważ, że celowo dodałem dodatkowe nawiasy w podpisie typu.
Zastosowania
($)
można zwykle wyeliminować przez dodanie nawiasów (chyba że w sekcji użyto operatora). Np .:f $ g x
staje sięf (g x)
.Zastosowania
(.)
są często nieco trudniejsze do zastąpienia; zazwyczaj potrzebują lambda lub wprowadzenia jawnego parametru funkcji. Na przykład:staje się
staje się
Mam nadzieję że to pomoże!
źródło
($)
umożliwia łączenie funkcji bez dodawania nawiasów w celu sterowania kolejnością oceny:Operator tworzenia
(.)
tworzy nową funkcję bez podawania argumentów:Powyższy przykład jest prawdopodobnie ilustracyjny, ale tak naprawdę nie pokazuje wygody używania kompozycji. Oto kolejna analogia:
Jeśli użyjemy trzeciego tylko raz, możemy uniknąć nazwania go za pomocą lambda:
Wreszcie, kompozycja pozwala nam uniknąć lambda:
źródło
Krótka i słodka wersja:
($)
wywołuje funkcję będącą argumentem po lewej stronie wartości, która jest argumentem po prawej stronie.(.)
tworzy funkcję będącą argumentem po lewej stronie funkcji, która jest argumentem po prawej stronie.źródło
Jedna aplikacja, która jest przydatna i zajęła mi trochę czasu, aby zrozumieć bardzo krótki opis na stronie hashell : Od:
a nawiasowanie prawej strony wyrażenia zawierającego operator infix przekształca go w funkcję prefiksu, którą można napisać
($ 3) (4+)
analogicznie(++", world") "hello"
.Dlaczego ktoś miałby to robić? Na przykład dla list funkcji. Obie:
i:
są krótsze niż
map (\x -> x ++ ", world") ...
lubmap (\f -> f 3) ...
. Oczywiście te ostatnie warianty byłyby bardziej czytelne dla większości ludzi.źródło
$3
bez przestrzeni. Jeśli szablon Haskell jest włączony, zostanie on przeanalizowany jako splot, a$ 3
zawsze oznacza to, co powiedziałeś. Ogólnie rzecz biorąc, wydaje się, że w Haskell istnieje tendencja do „kradzieży” fragmentów składni przez naleganie, aby niektórzy operatorzy mieli wokół siebie spacje, aby byli traktowani jako tacy.Są one nie cukrem syntaktycznym, ponieważ nie muszą używać nawiasów - są funkcjami, - naprawione, dlatego możemy nazwać je operatorami.
Komponować,
(.)
i kiedy z niego korzystać.(.)
to funkcja tworzenia. Więcjest równoznaczne z budowaniem funkcji, która przekazuje wynik argumentu przekazanego
g
dof
.Posługiwać się
(.)
gdy nie masz dostępnych argumentów do przekazania funkcji, które chcesz skomponować.Obowiązuje właściwy asocjator,
($)
i kiedy z nich korzystać($)
jest funkcją stosującą asocjację z niskim priorytetem wiązania. Więc najpierw oblicza tylko rzeczy po prawej stronie. A zatem,jest taki sam jak ten, proceduralnie (co ma znaczenie, ponieważ Haskell jest oceniany leniwie, zacznie oceniać jako
f
pierwszy):lub bardziej zwięźle:
Użyj,
($)
gdy masz wszystkie zmienne do oceny przed zastosowaniem poprzedniej funkcji do wyniku.Możemy to zobaczyć, czytając źródło dla każdej funkcji.
Przeczytaj źródło
Oto źródło dla
(.)
:A oto źródło dla
($)
:Wniosek
Użyj kompozycji, gdy nie musisz od razu oceniać funkcji. Może chcesz przekazać funkcję wynikającą ze składu do innej funkcji.
Użyj aplikacji, gdy podajesz wszystkie argumenty do pełnej oceny.
W naszym przykładzie byłoby to semantycznie lepsze
kiedy mamy
x
(a raczejg
argumenty) i wykonujemy:kiedy my nie.
źródło
... lub możesz uniknąć
.
i$
konstrukcji, używając rurociągów :To po dodaniu funkcji pomocnika:
źródło
$
operator faktycznie działa bardziej jak F # 's<|
niż to robi|>
, zazwyczaj w Haskell chcesz napisać powyższą funkcję tak:third xs = head $ tail $ tail $ xs
a może nawet jakthird = head . tail . tail
, co w F # -Style składnia byłoby coś takiego:let third = List.head << List.tail << List.tail
$
jest już dostępna, i to się nazywa&
hackage.haskell.org/package/base-4.8.0.0/docs/...Świetnym sposobem, aby dowiedzieć się więcej o czymkolwiek (dowolnej funkcji) jest zapamiętanie, że wszystko jest funkcją! Ta ogólna mantra pomaga, ale w szczególnych przypadkach, takich jak operatorzy, pomaga zapamiętać tę małą sztuczkę:
i
Pamiętaj tylko, aby używać
:t
swobodnie i owijać swoich operatorów()
!źródło
Moja zasada jest prosta (ja też jestem początkujący):
.
jeśli chcesz przekazać parametr (wywołać funkcję), i$
jeśli nie ma jeszcze parametru (utwórz funkcję)To jest
ale nigdy:
źródło
Myślę, że krótki przykład tego, gdzie byś użył
.
i nie$
pomógłby wyjaśnić rzeczy.Zauważ, że
times6
jest to funkcja utworzona z kompozycji funkcji.źródło
Wszystkie pozostałe odpowiedzi są całkiem dobre. Ale jest ważny szczegół użyteczności dotyczący tego, jak ghc traktuje $, że moduł sprawdzania typu ghc pozwala na instatiar z typami wyższego rzędu / ilościowymi. Jeśli spojrzysz na
$ id
przykład, zobaczysz, że przyjmie on funkcję, której argument sam w sobie jest funkcją polimorficzną. Takie małe rzeczy nie mają tej samej elastyczności z równorzędnym operatorem zdenerwowanym. (To sprawia, że zastanawiam się, czy $! Zasługuje na to samo traktowanie, czy nie)źródło