2014-10-31 9 views
5

Jestem nowy w F #. Błądziłem i znalazłem coś interesującego, i miałem nadzieję, że ktoś może mnie oświecić, co dzieje się za kulisami.Dlaczego funkcje są powiązane z pierwszym typem są przekazywane

Tak więc wykonałem funkcję: let my_func (x, y) = x + y.

Następnie wywołałem funkcję z argumentami 1 i 2, podając mi 3. Tak właśnie się spodziewałem, ale kiedy przeszedłem dwa ciągi do my_func, dostałem błąd, mimo że + jest prawidłowym operatorem z ciągami. Poprawiłem swój kod, ale tym razem zadzwoniłem pod numer my_func z "cat" i " dog", co dało mi "cat dog". Następnie próbowałem przekazać 1 i 2 z powrotem do my_func, aby stwierdzić, że my_func długo nie akceptuje liczb całkowitych.

Dlaczego zachowuje się w ten sposób my_func?

let my_func (x, y) = x + y
my_func (1, 2) // produces => 3
my_func ("cat", " dog") // Error

powtórka programu ...

let my_func (x, y) = x + y
my_func ("cat", " dog") // produces => "cat dog"
my_func (1, 2) // Error

Odpowiedz

8

@MarcinJuraszek pokazał, jak rozwiązać ten problem, ale nic nie powiedział o dlaczego zdarza.

Można myśleć o tym tak:

F # 's rodzaj wnioskowania działa góry do dołu, lewej do prawej - tak, gdy system próbuje odnaleźć typ dla my_func znajdzie je przypisać typy od w pierwszym wierszu, w którym używasz tej funkcji (pierwszy przykład to int s, a drugi to string s) - Jeśli w ogóle go nie użyjesz lub nie zdefiniujesz go w FSharp Interactive, będzie to domyślnie int.

Deklarowanie funkcji jako inline umożliwia F # korzystać statically resolved type parameters (z powodu pewnych informacji jest możliwe tylko inline funkcji), a następnie będzie ona rzeczywiście zrobić coś że potrzeby funkcyjnych kaczego wpisując dowiedzieć się z deklaracji typy, w których jakiś statyczny operator + jest zdefiniowany.

Można to zobaczyć w rodzaju funkcji:

val inline my_func : 
    x: ^a * y: ^b -> ^c 
    when (^a or ^b) : (static member (+) : ^a * ^b -> ^c) 

to dość skomplikowany typ mówi tylko to:

Nie może być statyczny operator (+) : ^a * ^b -> ^c na ^a (myślę 'a), który jest używany podczas pisania + w treści funkcji. Jak widać, jest to nawet bardziej ogólne, niż naprawdę tego potrzebujesz, ale to nie jest problem. F # zaimplementuje konkretne wersje (z podstawionymi typami podstawowymi) na wypadek wystąpienia tej funkcji, którą zastosujesz (w twoim przykładzie wystąpią dwie instancje my_func w twojej IL, jedna dla s i jedna dla String s) - ale to wygrało ' w ogóle nie przeszkadza ci w projektowaniu.

Więc masz teraz więcej rodzajowe funkcji, które mogą być używane w połączeniu z:

  • (+) : Int * Int -> Int na Int
  • (+) : String * String -> String na String
+1

+1 wielką odpowiedź. Se także [ten artykuł Liama ​​MCLennnana na podobnym gruncie] (http://withouttheloop.com/articles/2014-10-21-fsharp-adhoc-polymorphism/) –

Powiązane problemy