Aby odpowiedzieć na to pytanie, załóżmy, że koszt dwuznaczności w umyśle programisty jest znacznie droższy niż kilka dodatkowych naciśnięć klawiszy.
Biorąc to pod uwagę, dlaczego miałbym pozwalać moim kolegom z zespołu na ucieczkę bez adnotowania ich parametrów funkcji? Weź następujący kod jako przykład czegoś, co może być o wiele bardziej złożonym fragmentem kodu:
let foo x y = x + y
Teraz, szybkie sprawdzenie podpowiedzi pokaże, że F # ustaliło, że chciałeś, aby xiy były ints. Jeśli tak zamierzałeś, wszystko jest w porządku. Ale ja nie wiem, czy to, co zamierzałeś. Co jeśli utworzyłeś ten kod, aby połączyć dwa ciągi razem? A co jeśli myślę, że prawdopodobnie chciałeś dodać podwójne? A jeśli nie chcę po prostu najeżdżać myszką na każdy parametr funkcji, aby określić jej typ?
Teraz weź to jako przykład:
let foo x y = "result: " + x + y
F # zakłada teraz, że prawdopodobnie zamierzałeś łączyć łańcuchy, więc xiy są zdefiniowane jako łańcuchy. Jednak jako biedny schmuck, który utrzymuje Twój kod, mogę na to spojrzeć i zastanawiać się, czy być może nie chciałeś dodać x i y (int) razem, a następnie dołączyć wynik do ciągu dla celów interfejsu użytkownika.
Z pewnością w przypadku takich prostych przykładów można to odpuścić, ale dlaczego nie narzucić polityki wyraźnych adnotacji typu?
let foo (x:string) (y:string) = "result: " + x + y
Jaka jest szkoda w jednoznaczności? Pewnie, programista może wybrać niewłaściwe typy do tego, co próbują zrobić, ale przynajmniej wiem, że zamierzali to zrobić, że to nie był tylko przeoczenie.
To poważne pytanie ... Nadal jestem nowy na F # i wytyczam szlak dla mojej firmy. Standardy, które przyjmę, będą prawdopodobnie podstawą wszystkich przyszłych kodowań F #, osadzonych w nieskończonym kopiowaniu, które z pewnością przenikną do kultury przez wiele lat.
Więc ... czy jest coś specjalnego w wnioskowaniu typu F #, co czyni z niego cenną funkcję do trzymania, adnotację tylko w razie potrzeby? A może eksperci F # mają zwyczaj dodawania adnotacji do swoich parametrów w nie trywialnych zastosowaniach?
źródło
Odpowiedzi:
Nie używam F #, ale w Haskell uważa się za dobrą formę adnotacji (przynajmniej) definicji najwyższego poziomu, a czasem definicji lokalnych, nawet jeśli język ma wszechobecne wnioskowanie o typach. Jest to z kilku powodów:
Czytanie
Jeśli chcesz wiedzieć, jak korzystać z funkcji, niezwykle przydatna jest dostępność podpisu typu. Możesz to po prostu przeczytać, zamiast próbować wnioskować o tym samemu lub polegać na narzędziach, które zrobią to za Ciebie.
Refaktoryzacja
Jeśli chcesz zmienić funkcję, posiadanie wyraźnego podpisu daje pewną pewność, że Twoje transformacje zachowają intencję oryginalnego kodu. W języku opartym na typach może się okazać, że wysoce polimorficzny kod sprawdzi typ, ale nie zrobi tego, co zamierzałeś. Podpis typu jest „barierą”, która konkretyzuje informacje o typie w interfejsie.
Wydajność
W Haskell wywnioskowany typ funkcji może być przeciążony (za pomocą klas), co może oznaczać wysłanie w czasie wykonywania. W przypadku typów numerycznych domyślnym typem jest liczba całkowita o dowolnej dokładności. Jeśli nie potrzebujesz pełnej ogólności tych funkcji, możesz poprawić wydajność, specjalizując funkcję dla określonego typu, którego potrzebujesz.
W przypadku definicji lokalnych,
let
zmiennych związanych i parametrów formalnych do lambd, uważam, że podpisy typu zwykle kosztują więcej w kodzie niż wartość, którą dodaliby . Dlatego podczas przeglądu kodu sugerowałbym, aby nalegać na podpisy dla definicji najwyższego poziomu i po prostu poprosić o rozsądne adnotacje w innym miejscu.źródło
.mli
pliku interface ( ) (jeśli piszesz takie, do których jesteś bardzo zachęcany. Adnotacje typu są zwykle pomijane w definicjach, ponieważ byłyby zbędne z interfejsem..fsi
plikach F # Signature ( ), z jednym zastrzeżeniem: F # nie używa plików podpisu do wnioskowania o typie, więc jeśli coś w implementacji jest niejednoznaczne, nadal będziesz musiał to zrobić. books.google.ca/…Jon udzielił rozsądnej odpowiedzi, której nie powtórzę tutaj. Pokażę ci jednak opcję, która może zaspokoić twoje potrzeby, a podczas tego procesu zobaczysz inny rodzaj odpowiedzi niż tak / nie.
Ostatnio pracuję nad analizowaniem składni za pomocą kombinatorów parsera. Jeśli znasz parsowanie, to wiesz, że zazwyczaj używasz leksykera w pierwszej fazie i parsera w drugiej fazie. Lexer konwertuje tekst na tokeny, a parser konwertuje tokeny na AST. Teraz, gdy F # jest językiem funkcjonalnym, a kombinatory są zaprojektowane do łączenia, kombinatory parsera są zaprojektowane do korzystania z tych samych funkcji zarówno w leksyrze, jak i parserze, ale jeśli ustawisz typ funkcji kombinatora parsera, możesz ich użyć tylko do leksykon lub parsowanie, a nie jedno i drugie.
Na przykład:
lub
Ponieważ kod jest chroniony prawem autorskim, nie dołączę go tutaj, ale jest dostępny na Github . Nie kopiuj go tutaj.
Aby funkcje działały, należy pozostawić ogólne parametry, ale dołączam komentarze, które pokazują wywnioskowane typy w zależności od użycia funkcji. Ułatwia to zrozumienie funkcji konserwacji, pozostawiając ogólną funkcję do użycia.
źródło
Liczba błędów jest wprost proporcjonalna do liczby znaków w programie!
Zazwyczaj określa się to jako liczbę błędów proporcjonalną do linii kodu. Ale posiadanie mniejszej liczby wierszy z taką samą ilością kodu daje taką samą liczbę błędów.
Więc chociaż miło jest wyrazić się jasno, wszelkie dodatkowe parametry, które wpisujesz, mogą prowadzić do błędów.
źródło