2008-09-19 14 views
23

Próbowałem od czasu do czasu włączać i wyłączać funkcję F #, ale ciągle się odkładam. Czemu?Co oznacza -> znaczy w F #?

Ponieważ niezależnie od tego, z jakiego zasobu "początkujących" próbuję spojrzeć, widzę bardzo proste przykłady, które zaczynają używać operatora ->.

Nigdzie jednak nie znalazłem jeszcze jednoznacznego wyjaśnienia, co oznacza ten operator. To tak, jakby musiało być tak oczywiste, że nie potrzebuje wyjaśnień nawet w celu uzupełnienia początkujących.

Muszę więc być naprawdę gęsty, a może już prawie trzy dekady poprzedniego doświadczenia powstrzymywało mnie.

Czy ktoś może, proszę wyjaśnić lub wskazać prawdziwie dostępny zasób, który to wyjaśnia?

+0

To wszystko wydaje mi się również greckie. – Brettski

+0

Nazwij go po prostu Matuzalem. –

+0

W rzeczywistości Matuzalem żył przez 969 lat, więc nadal byłbym jedną trzecią jego wieku. Jednak edytowane dziękuję;) – AnthonyWJones

Odpowiedz

46

'->' nie jest operatorem. Pojawia się w składni F # w wielu miejscach, a jej znaczenie zależy od tego, w jaki sposób jest on używany jako część większego konstruktu.

Wewnątrz typu "->" opisuje typy funkcji opisane powyżej. Na przykład:

let f : int -> int = ... 

mówi, że "f" jest funkcją, która przyjmuje int i zwraca int.

Wewnątrz lambda ("rzecz zaczynająca się od słowa" zabawa ")," -> "to składnia oddzielająca argumenty od ciała. Na przykład:

fun x y -> x + y + 1 

to wyrażenie, które definiuje funkcję dwóch argumentów z daną implementacją.

Wewnątrz konstruktu "dopasowującego", "->" jest składnią oddzielającą wzorce od kodu, który powinien zostać uruchomiony, jeśli wzór jest dopasowany. Na przykład, w

match someList with 
| [] -> 0 
| h::t -> 1 

rzeczy na lewo od każdego „->” są wzory, a rzeczy po prawej stronie jest to, co się dzieje, jeśli wzór po lewej stronie został dopasowany.

Trudności w zrozumieniu mogą wynikać z błędnego założenia, że ​​"->" jest "operatorem" o jednym znaczeniu. Analogią może być "." w C#, jeśli nigdy wcześniej nie widziałeś żadnego kodu i spróbuj przeanalizować "." Operator oparty na metodzie "obj.Method" i "3.14" oraz "System.Collections" może być bardzo zdezorientowany, ponieważ symbol ma różne znaczenia w różnych kontekstach. Kiedy jednak już znasz język, aby rozpoznać te konteksty, wszystko stanie się jasne.

+0

Zaakceptowałem to jako odpowiedź, ponieważ jest to odpowiednik tego rodzaju odpowiedzi, której szukałem, ale tam jest wiele innych szczegółów z innych udzielonych odpowiedzi. Nie podoba mi się, że -> nie jest jednak operatorem. Czy ktoś inny może to potwierdzić? – AnthonyWJones

+2

Można powiedzieć, że jest to operator poziomu. Raczej konstruktor typów danych. (a -> b) jest izomorficzne z (a, b). Strzała w pierwszym jest tym samym, co przecinek w drugim. – Apocalisp

+0

Apocalisp, zajęło mi kilka odczytów (zakładając, że wiedziałem, że izometryczny środek powstrzymywał mnie), ale mam to teraz. – AnthonyWJones

12

W skrócie oznacza "mapy do". Przeczytaj to w ten sposób lub "przekształca się w" lub coś podobnego.

Tak więc, z poradnika F# in 20 minutes,

> List.map (fun x -> x % 2 = 0) [1 .. 10];; 
val it : bool list 
= [false; true; false; true; false; true; false; true; false; true] 

kod (zabawy i -> I% 2 = 0) określa anonimowy funkcja zwana lambda ekspresji, który zawiera parametr X i funkcja zwraca wynik "x % 2 = 0", czyli czy wartość x jest równa .

+0

Można również użyć tego odsyłacza: http://research.microsoft.com/fsharp/manual/lexyacc.aspx –

1

Od Microsoft:

typy funkcyjne są rodzaje podane do wartościami funkcji pierwszej klasy i są napisany int -> int. Są one podobne do typów delegatów .NET, z tym że nie mają podanych nazw. Wszystkie funkcje F # mogą być używane jako pierwszorzędne wartości funkcji , a anonimowe wartości funkcji mogą być tworzone za pomocą formularza wyrażenia (fun ... -> ...).

4

(a -> b) oznacza "funkcję od a do b". W adnotacji typu oznacza typ funkcji. Na przykład f: (int -> String) oznacza, że ​​f odnosi się do funkcji, która pobiera liczbę całkowitą i zwraca ciąg znaków. Jest także używany jako contstructor takich wartości, jak w

val f : (int -> int) = fun n -> n * 2 

który tworzy wartość, która jest funkcją liczby n z jakiegoś do tej samej liczby pomnożone przez dwa.

0

Fajna rzecz w językach takich jak Haskell (jest bardzo podobny w F #, ale nie znam dokładnej składni - to powinno pomóc ci zrozumieć ->, chociaż) jest to, że możesz zastosować tylko części argumentu , aby utworzyć curried funkcje:

adder n x y = n + x + y 

innymi słowy: "daj mi trzy rzeczy, i dodam je razem". Podczas rzucania liczbami, kompilator wywnioskuje typy n x i y.Załóżmy, że piszesz:

adder 1 2 3 

Typ 1, 2 i 3 to liczba wewnętrzna. Dlatego:

adder :: Int -> Int -> Int -> Int 

Oznacza to, że dał mi trzy liczby całkowite, i stanę liczbę całkowitą, ewentualnie, czy samo jak powiedzenie:

five :: Int 
five = 5 

Ale tu jest ładny część! Wypróbuj to:

add5 = adder 5 

Pamiętaj, że sumator przyjmuje int, int, int i daje z powrotem int. Jednak to nie jest cała prawda, jak się wkrótce przekonacie. W rzeczywistości, add5 będzie miał tego typu:

add5 :: Int -> Int -> Int 

Będzie tak, jeśli „odkleić” od liczb całkowitych (lewy-większość) i przyklejona bezpośrednio do funkcji. Patrząc bliżej na podpis funkcji, możemy zauważyć, że -> rację-asocjacyjne, tj:

addder :: Int -> (Int -> (Int -> Int)) 

ten powinien uczynić to całkiem jasne: gdy dajesz Adder najbliższej liczby całkowitej, to będzie ocenić na wszystko co do prawo od pierwszej strzałki, lub:

add5andtwomore :: Int -> (Int -> Int) 
add5andtwomore = adder 5 

Teraz możesz użyć add5andtwomore zamiast "adder 5". W ten sposób, można zastosować inną liczbę całkowitą, aby uzyskać (powiedzmy) „add5and7andonemore”:

add5and7andonemore :: Int -> Int 
add5and7andonemore = adder 5 7 

Jak widać, add5and7andonemore chce dokładnie kolejny argument, a kiedy dać mu jedną, to nagle staje się liczbą całkowitą!

> add5and7andonemore 9 
=> ((add5andtwomore) 7) 9 
=> ((adder 5) 7) 9) 
<=> adder 5 7 9 

Podstawiając parametry do sumatora (nxy) do (5 7 9), otrzymujemy:

> adder 5 7 9 = 5 + 7 + 9 
=> 5 + 7 + 9 
=> 21 

W rzeczywistości, plusem jest też po prostu funkcja, która trwa int i daje wróć do innej strony, więc powyższe jest bardziej podobne:

> 5 + 7 + 9 
=> (+ 5 (+ 7 9)) 
=> (+ 5 16) 
=> 21 

Proszę!

1

Jest tu już wiele wspaniałych odpowiedzi, po prostu chcę dodać do rozmowy inny sposób myślenia o tym.

"->" oznacza funkcję.

'A ->' b jest funkcja, która bierze 'a i zwraca 'b

(' A * 'b) -> (' c *', d) jest funkcją, która przyjmuje krotki typu ("a," b) i zwraca krotkę ("c," d). Takich jak int/string zwraca float/char.

Tam, gdzie jest to interesujące, jest w kaskadowym przypadku "a ->" b -> "c. Jest to funkcja, która przyjmuje "a i zwraca funkcję (" b -> "c) lub funkcję, która przyjmuje" b -> "c.

Więc jeśli piszesz: niech fxyz =()

typ zostanie F: 'a ->' b -> „c -> jednostki, więc jeśli tylko zastosowano pierwszy parametr, wynik byłaby funkcją curried "b ->" c -> "jednostka.

1

W kontekście definiowania funkcji jest ona podobna do => z wyrażenia lambda w C# 3.0.

F#: let f = fun x -> x*x 
C#: Func<int, int> f = x => x * x; 

-> w F # jest również stosowany w dopasowywania wzorców, gdzie to znaczy: jeśli wyrażenie pasuje część między | i ->, to co przychodzi po -> powinna być zwrócona w wyniku:

let isOne x = match x with 
| 1 -> true 
| _ -> false 
9

Pierwsze pytanie - czy znasz wyrażenia lambda w języku C#? Jeśli tak, to -> w F # jest takie samo jak => w C# (myślę, że to czytasz "idzie do").

The -> operator można znaleźć również w kontekście wzór pasujący

match x with 
| 1 -> dosomething 
| _ -> dosomethingelse 

Nie jestem pewien, czy jest to również wyrażenie lambda, czy coś innego, ale Myślę, że „idzie” wciąż trzyma.

Może to, czego naprawdę powołując się to „tajemnicze” Odpowiedzi na F # parser jest:

> let add a b = a + b 
val add: int -> int -> int 

oznacza to (jak większość przykładów wyjaśnić), które dodają to „val”, który trwa dwa ints i powroty int. Dla mnie było to całkowicie nieprzejrzyste na początek. Mam na myśli, skąd mam wiedzieć, że add nie jest val, który ma jeden int i zwraca dwa ints?

Cóż, chodzi o to, że w pewnym sensie tak jest. Jeśli dam dodać tylko jeden int, wrócę An (int -> int):

> let inc = add 1 
val inc: int -> int 

To (Zmiękczanie) jest jedną z rzeczy, która sprawia, że ​​F # tak sexy, dla mnie.

Pomocne informacje na F #, odkryłem, że blogi są znacznie bardziej użyteczne, że którykolwiek z oficjalnej „dokumentacji”: Oto niektóre nazwy, aby sprawdzić

1

Wiele wspaniałych odpowiedzi na to pytanie, dzięki ludziom. Chciałbym umieścić tutaj edytowalną odpowiedź, która łączy wszystko.

Dla osób znających C# zrozumienie -> bycie takim samym jak => wyrażenie lamba to dobry pierwszy krok. Ten zwyczaj jest: -

fun x y -> x + y + 1 

może być rozumiana jako odpowiednik: -

(x, y) => x + y + 1; 

Jednak jej jasne, że -> ma bardziej fundemental znaczenie, jakie wynika z koncepcji, że funkcja, która przyjmuje dwa parametry takie jak powyższe można zmniejszyć (jest to poprawny termin?) do szeregu funkcji, przyjmując tylko jeden parametr.

Stąd, gdy powyżej opisany jest w ten sposób: -

Int -> Int -> Int 

To naprawdę pomogło wiedzieć, że -> ma rację asocjacyjne stąd powyższe można uznać: -

Int -> (Int -> Int) 

Aha! Mamy funkcję, która przyjmuje Int i zwraca (Int -> Int) (funkcja curried?).

Wyjaśnienie, które -> może również pojawić się jako część definicji typu, również pomogło. (Int -> Int) jest typem dowolnej funkcji, która przyjmuje wartość Int i zwraca wartość Int.

Pomocne jest również -> pojawia się w innej składni takiej jak dopasowanie, ale nie ma tego samego znaczenia? Czy to jest poprawne? Nie jestem pewien. Podejrzewam, że ma to samo znaczenie, ale nie mam słownictwa, aby to wyrazić.

Uwaga: celem tej odpowiedzi nie jest odradzanie dalszych odpowiedzi, ale wspólne edytowanie przez Ciebie osób w celu uzyskania bardziej ostatecznej odpowiedzi. W sumie dobrze byłoby usunąć wszystkie niepewności i błędy (takie jak ten akapit) i dodać lepsze przykłady. Spróbujmy, aby ta odpowiedź była dostępna dla niewtajemniczonych, jak to tylko możliwe.

+0

Będę wracał, kiedy mam wystarczająco dużo reputacji :) – Benjol

+0

Tak więc w definicji typu - Int -> Int -> Int = func, która przyjmuje int i zwraca funkcję, która przyjmuje int i zwraca int - is to prawda? –