Właśnie zacząłem patrzeć na ponowną implementację biblioteki kolekcji Scala, która będzie dostępna w najbliższym wydaniu 2.8 . Osoby zaznajomione z biblioteką od 2.7 zauważą, że biblioteka, z perspektywy użytkowania, niewiele się zmieniła. Na przykład...
> List("Paris", "London").map(_.length)
res0: List[Int] List(5, 6)
... działałby w obu wersjach. Biblioteka jest niezwykle użyteczna : w rzeczywistości jest fantastyczna. Jednak ci, którzy wcześniej nie znali Scali i szukali języka, muszą teraz zrozumieć podpisy metod, takie jak:
def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Repr, B, That]): That
Jak na tak prostą funkcjonalność, jest to zniechęcający podpis, który trudno mi zrozumieć. Nie dlatego, że uważam, że Scala prawdopodobnie będzie kolejną Javą (lub / C / C ++ / C #) - nie sądzę, aby jej twórcy celowali w nią na tym rynku - ale myślę, że Scala jest / z pewnością wykonalna następny Ruby lub Python (tj. aby zdobyć znaczącą bazę użytkowników komercyjnych)
- Czy to zniechęci ludzi do Scali?
- Czy w ten sposób Scala zyska złą sławę w świecie komercyjnym jako akademicka gra, którą zrozumieją tylko oddani doktoranci? Czy CTO i szefowie oprogramowania będą się odstraszyć?
- Czy przeprojektowanie biblioteki było rozsądnym pomysłem?
- Jeśli używasz Scali w celach komercyjnych, martwisz się tym? Czy planujesz od razu zastosować 2.8 lub poczekać, aby zobaczyć, co się stanie?
Steve Yegge zaatakował kiedyś Scalę (moim zdaniem przez pomyłkę) za to, co uważał za zbyt skomplikowany system typów. Martwię się, że ktoś będzie miał dzień polowy rozpowszechniający FUD za pomocą tego API (podobnie jak Josh Bloch przestraszył JCP przed dodaniem zamknięć do Javy).
Uwaga - powinienem jasno powiedzieć, że chociaż uważam, że Joshua Bloch miał wpływ na odrzucenie propozycji zamknięcia BGGA, nie przypisuję tego nikomu innemu niż jego szczerym przekonaniom, że propozycja stanowi błąd.
Pomimo tego, co powtarzają mi moja żona i współpracownicy, nie uważam się za idiotę: mam dobry dyplom z matematyki na Uniwersytecie Oksfordzkim i programuję od prawie 12 lat, aw Scali od około rok (także komercyjnie).
Zwróć uwagę, że tytuł tematu zapalnego jest cytatem na temat manifestu brytyjskiej partii politycznej na początku lat osiemdziesiątych . To pytanie jest subiektywne, ale jest to prawdziwe pytanie. Uczyniłem je CW i chciałbym uzyskać jakieś opinie w tej sprawie.
źródło
Odpowiedzi:
Mam nadzieję, że to nie jest „notatka samobójcza”, ale rozumiem twój punkt widzenia. Uderzasz w to, co jest jednocześnie siłą i problemem Scali: jej rozszerzalności . To pozwala nam zaimplementować większość głównych funkcji w bibliotekach. W niektórych innych językach sekwencje z czymś takim
map
lubcollect
byłyby wbudowane i nikt nie musi widzieć wszystkich obręczy, przez które musi przejść kompilator, aby działały płynnie. W Scali wszystko jest w bibliotece, a zatem na zewnątrz.W rzeczywistości funkcjonalność
map
obsługiwana przez jego skomplikowany typ jest dość zaawansowana. Rozważ to:Zobacz, jak zawsze dostajesz najlepszy możliwy typ? Jeśli zamapujesz
Int
s naInt
s, otrzymasz ponownie aBitSet
, ale jeśli zmapujeszInt
s naString
s, otrzymasz generałaSet
. Zarówno typ statyczny, jak i reprezentacja środowiska wykonawczego wyniku mapy zależą od typu wyniku przekazanej do niej funkcji. I to działa, nawet jeśli zestaw jest pusty, więc funkcja nigdy nie jest stosowana! O ile mi wiadomo, nie ma innej struktury kolekcji o równoważnej funkcjonalności. Jednak z perspektywy użytkownika tak właśnie powinno działać.Problem, jaki mamy, polega na tym, że cała sprytna technologia, która sprawia, że tak się dzieje, przecieka do podpisów, które stają się duże i przerażające. Ale może użytkownik nie powinien wyświetlać domyślnie pełnego podpisu typu
map
? Jak o tym, czy spojrzałamap
wBitSet
Dostała:Dokumenty nie leżą w takim przypadku, ponieważ z perspektywy użytkownika mapa rzeczywiście ma taki typ
(Int => Int) => BitSet
. Alemap
ma też bardziej ogólny typ, który można sprawdzić, klikając inny link.Nie wdrożyliśmy jeszcze takiej funkcjonalności w naszych narzędziach. Uważam jednak, że musimy to zrobić, aby uniknąć odstraszania ludzi i podać bardziej przydatne informacje. Dzięki takim narzędziom, mam nadzieję, że inteligentne frameworki i biblioteki nie staną się notatkami samobójczymi.
źródło
Nie mam doktoratu, ani żadnego innego stopnia, ani z CS, ani z matematyki, ani też żadnej innej dziedziny. Nie mam wcześniejszego doświadczenia ze Scalą ani innym podobnym językiem. Nie mam doświadczenia w nawet zdalnie porównywalnych systemach typu. W rzeczywistości, jedynym językiem, że mam więcej niż tylko powierzchowną wiedzę z których nawet ma system typu jest Pascal, nie do końca znany ze swojego skomplikowanego systemu typu. (Mimo, że nie mają typów zakresu, który AFAIK prawie żaden inny język ma, ale to naprawdę nie jest istotne tutaj). Pozostałe trzy języki, których znam są podstawowe, Smalltalk i Ruby, z których żadna nie mają nawet system typu.
A jednak nie mam żadnych problemów ze zrozumieniem podpisu
map
opublikowanej funkcji. Wygląda mi na prawie taki sam podpis, jakmap
w każdym innym języku, jaki kiedykolwiek widziałem. Różnica polega na tym, że ta wersja jest bardziej ogólna. Wygląda bardziej jak C ++ STL niż, powiedzmy, Haskell. W szczególności abstrahuje od konkretnego typu kolekcji, wymagając jedynie podania argumentuIterableLike
, a także abstrahuje od konkretnego typu zwrotu, wymagając jedynie istnienia niejawnej funkcji konwersji, która może zbudować coś z tej kolekcji wartości wynikowych. Tak, jest to dość skomplikowane, ale tak naprawdę jest tylko wyrazem ogólnego paradygmatu programowania ogólnego: nie zakładaj niczego, czego tak naprawdę nie musisz.W takim przypadku kolekcja
map
nie musi być listą, uporządkowana, sortowalna ani nic podobnego. Jedyną rzeczą, na którejmap
zależy, jest to, że może uzyskać dostęp do wszystkich elementów kolekcji, jeden po drugim, ale nie w określonej kolejności. I nie musi wiedzieć, jaka jest wynikowa kolekcja, musi tylko wiedzieć, jak ją zbudować. Tak więc tego wymaga podpis typu.Więc zamiast
który jest tradycyjnym typem podpisu
map
, uogólniono go, aby nie wymagał konkretnej,List
a jedynieIterableLike
struktury danychktóry jest następnie uogólniany poprzez wymaganie tylko istnienia funkcji, która może przekonwertować wynik na dowolną strukturę danych, jakiej chce użytkownik:
Przyznaję, że składnia jest nieco dziwniejsza, ale semantyka jest taka sama. Zasadniczo zaczyna się od
który jest tradycyjnym podpisem dla
map
. (Zwróć uwagę, jak z uwagi na obiektową naturę Scali parametr listy wejściowej znika, ponieważ jest to domyślny parametr odbiornika, który ma każda metoda w systemie OO z pojedynczą wysyłką.) Następnie uogólniono go z konkretnegoList
na bardziej ogólnyIterableLike
Teraz zastępuje
IterableLike
kolekcję wyników funkcją, która generuje , właściwie, właściwie wszystko.W co naprawdę wierzę, nie jest to takie trudne do zrozumienia. Tak naprawdę potrzebujesz tylko kilku narzędzi intelektualnych:
map
jest. Przyznaję, że gdybyś podał tylko podpis typu bez nazwy metody, znacznie trudniej byłoby ustalić, co się dzieje. Ale skoro już wiesz, comap
należy zrobić i wiesz, jaki powinien być podpis typu, możesz szybko zeskanować podpis i skupić się na anomaliach, na przykład „dlaczegomap
bierze to dwie funkcje za argument, a nie jedną?”.Żadna z tych trzech nie powinna sprawić poważnego bólu głowy żadnemu profesjonalnemu, a nawet hobbystycznemu programistowi.
map
był standardową funkcją w prawie każdym języku zaprojektowanym w ciągu ostatnich 50 lat, fakt, że różne języki mają różną składnię, powinien być oczywisty dla każdego, kto zaprojektował stronę internetową z HTML i CSS i nie można subskrybować nawet zdalnego programowania powiązana lista mailingowa bez denerwujących fanów C ++ z kościoła św. Szczepana wyjaśniających zalety programowania ogólnego.Tak, Scala jest złożona. Tak, Scala ma jeden z najbardziej wyrafinowanych systemów typowych znanych człowiekowi, rywalizujących, a nawet przewyższających języki, takie jak Haskell, Miranda, Clean lub Cyclone. Gdyby jednak złożoność była argumentem przeciwko sukcesowi języka programowania, C ++ umarłby dawno temu i wszyscy pisalibyśmy schemat. Istnieje wiele powodów, dla których Scala najprawdopodobniej nie odniesie sukcesu, ale fakt, że programiści nie będą mieli kłopotów z włączeniem mózgu przed siadaniem przed klawiaturą, prawdopodobnie nie będzie głównym.
źródło
That
wnioskowanie i powiązanie z typemB
jest jednym pytaniem, które przychodzi na myśl. Gdzie są implikacje wynikające z bycia innym. Nawet bez tych szczegółowych obserwacji nadal osobiście uważam, że jest to złożony podpis. Ale najwyraźniej są tacy ludzie jak ty, którzy wcale nie są tym zaskoczeni!To samo w C ++ :
źródło
func
powinien być parametrem szablonu, a powinieneś użyćresult_of
i,is_callable
aby uzyskać inne typy i odpowiednio ograniczyć zestaw przeciążeń :-)Cóż, rozumiem twój ból, ale, szczerze mówiąc, ludzie tacy jak ty i ja - lub właściwie każdy zwykły użytkownik stosu przepełnienia stosu - nie są regułą.
Rozumiem przez to, że ... większość programistów nie będzie obchodzić tego typu podpisu, ponieważ nigdy go nie zobaczą ! Nie czytają dokumentacji.
Tak długo, jak zobaczyli jakiś przykład działania kodu, a kod nie zawiedzie ich w uzyskaniu oczekiwanego rezultatu , nigdy nie spojrzy na dokumentację. Kiedy to się nie powiedzie, przejrzą dokumentację i spodziewają się przykładów użycia u góry.
Mając to na uwadze, myślę, że:
Każdy (jak większość ludzi), który kiedykolwiek spotka się z tego rodzaju sygnaturą, będzie kpił ze Scali bez końca, jeśli będzie miał do niej uprzedzenia, i uzna to za symbol mocy Scali, jeśli podoba im się Scala.
Jeśli dokumentacja nie zostanie ulepszona w celu dostarczenia przykładów użycia i jasnego wyjaśnienia, do czego służy metoda i jak z niej korzystać, może to nieco pogorszyć adopcję Scali.
Na dłuższą metę nie będzie to miało znaczenia. To, że Scala może robić takie rzeczy, sprawi, że biblioteki napisane dla Scali będą znacznie wydajniejsze i bezpieczniejsze w użyciu. Te biblioteki i frameworki przyciągną programistów zainteresowanych potężnymi narzędziami.
Programiści, którzy lubią prostotę i bezpośredniość, będą nadal używać PHP lub podobnych języków.
Niestety, programiści Java interesują się elektronarzędziami, więc odpowiadając na to, właśnie zrewidowałem moje oczekiwania dotyczące głównego nurtu Scali. Nie mam wątpliwości, że Scala stanie się głównym językiem. Nie C-mainstream, ale być może Perl-mainstream lub PHP-mainstream.
Mówiąc o Javie, czy kiedykolwiek zastąpiłeś moduł ładujący klasy? Czy kiedykolwiek zastanawiałeś się, co to obejmuje? Java może być przerażająca, jeśli spojrzysz na miejsca, które robią autorzy frameworka. Po prostu większość ludzi tego nie robi. To samo dotyczy Scali, IMHO, ale wcześni użytkownicy mają tendencję do zaglądania pod każdą napotkaną skałę, aby sprawdzić, czy coś się tam ukrywa.
źródło
As long as they saw some example of how the code works, and the code doesn't fail them in producing the result they expect, they won't ever look at the documentation. When that fails, they'll look at the documentation and expect to see usage examples at the top.
Smutne ale prawdziwe.Tak, ale zapobiegnie to również odkładaniu ludzi. Uważam, że brak zbiorów wykorzystujących typy wyższego rodzaju jest główną słabością, odkąd Scala uzyskała wsparcie dla typów wyższego rodzaju. To sprawia, że dokumenty API są bardziej skomplikowane, ale tak naprawdę sprawia, że korzystanie z nich jest bardziej naturalne.
Niektórzy prawdopodobnie będą. Nie sądzę, aby Scala była dostępna dla wielu „profesjonalnych” programistów, częściowo ze względu na złożoność Scali, a częściowo z powodu niechęci wielu programistów do nauki. CTO, którzy zatrudniają takich programistów, będą słusznie wystraszeni.
Absolutnie. Sprawia, że kolekcje są znacznie lepiej dopasowane do reszty języka i systemu czcionek, nawet jeśli nadal mają ostre krawędzie.
Nie używam tego komercyjnie. Prawdopodobnie poczekam, aż co najmniej kilka z nich przejdzie do serii 2.8.x, zanim spróbuję go wprowadzić, aby błędy mogły zostać usunięte. Będę również czekał, aby zobaczyć, jak duży sukces EPFL poprawia proces wydawania. To, co widzę, wygląda na obiecujące, ale pracuję dla konserwatywnej firmy.
Jednym z bardziej ogólnych tematów „czy Scala jest zbyt skomplikowana dla głównych programistów?” ...
Większość programistów, głównego nurtu lub w inny sposób, utrzymuje lub rozbudowuje istniejące systemy. Oznacza to, że większość tego, czego używają, jest podyktowana decyzjami podjętymi dawno temu. Nadal wiele osób pisze w języku COBOL.
Jutro główny programista będzie pracował nad utrzymywaniem i rozszerzaniem aplikacji, które są obecnie budowane. Wiele z tych aplikacji nie jest budowanych przez głównych programistów. Jutro programiści głównego nurtu będą używać języka, który jest używany przez najbardziej udanych programistów nowych aplikacji.
źródło
Jednym ze sposobów, w jaki społeczność Scali może pomóc w zmniejszeniu strachu przed nowymi programistami w Scali, jest skupienie się na praktyce i nauczanie poprzez przykład - wiele przykładów, które zaczynają się od małych i stopniowo stają się coraz większe. Oto kilka witryn, które stosują to podejście:
Po spędzeniu czasu na tych stronach szybko zdaje sobie sprawę, że Scala i jej biblioteki, choć być może trudne do zaprojektowania i wdrożenia, nie są tak trudne w użyciu, szczególnie w zwykłych przypadkach.
źródło
Mam licencjat z taniego amerykańskiego uniwersytetu na „masowym rynku”, więc powiedziałbym, że wpadam w sam środek skali inteligencji użytkowników (a przynajmniej edukacji) :) Zajmuję się Scalą zaledwie kilka miesięcy i pracowali nad dwoma lub trzema nietrywialnymi aplikacjami.
Zwłaszcza teraz, gdy IntelliJ wydało swoje dobre IDE z tym, co IMHO jest obecnie najlepszą wtyczką Scali, rozwój Scali jest stosunkowo bezbolesny:
Uważam, że mogę używać Scali jako „Java bez średników”, tj. Piszę podobny wygląd do tego, co robię w Javie, i czerpię trochę korzyści z zwięzłości syntaktycznej, takiej jak ta uzyskana na podstawie wnioskowania o typie. Obsługa wyjątków, gdy w ogóle to robię, jest wygodniejsza. Definicja klasy jest znacznie mniej szczegółowa bez płyty kotłowej gettera / setera.
Raz na jakiś czas udaje mi się napisać jedną linię, aby uzyskać równowartość wielu linii Java. Tam, gdzie ma to zastosowanie, łańcuchy funkcjonalnych metod, takich jak mapowanie, składanie, zbieranie, filtrowanie itp., Są zabawne w komponowaniu i eleganckie.
Rzadko zdarza mi się czerpać korzyści z bardziej zaawansowanych funkcji Scali: zamknięć i funkcji częściowych (lub curry), dopasowywania wzorców ... tego rodzaju rzeczy.
Jako nowicjusz nadal walczę ze zwięzłą i idiomatyczną składnią. Wywołania metod bez parametrów nie wymagają nawiasów, chyba że wymagają; przypadki w instrukcji match wymagają grubej strzałki (
=>
), ale są też miejsca, w których potrzebujesz cienkiej strzałki (->
). Wiele metod ma krótkie, ale raczej tajemnicze nazwy, takie jak/:
lub\:
- mogę załatwić sprawę, jeśli przewrócę wystarczającą liczbę stron podręcznika, ale niektóre z moich kodów wyglądają jak Perl lub szum linii. Jak na ironię brakuje jednego z najpopularniejszych fragmentów skróconej składni w działaniu: gryzie mnie fakt, żeInt
nie definiuje++
metody.To tylko moja opinia: czuję, że Scala ma moc C ++ w połączeniu ze złożonością i czytelnością C ++. Złożoność składniowa języka sprawia również, że dokumentacja API jest trudna do odczytania.
Scala jest bardzo przemyślana i genialna pod wieloma względami. Podejrzewam, że wielu naukowców chętnie by w tym programowało. Jednak jest też pełen sprytu i gotów, ma znacznie wyższą krzywą uczenia się niż Java i jest trudniejszy do odczytania. Jeśli przejrzę fora i zobaczę, ilu programistów wciąż zmaga się z drobniejszymi aspektami Javy, nie wyobrażam sobie, by Scala stała się językiem głównego nurtu . Żadna firma nie będzie w stanie uzasadnić wysłania programistów na 3-tygodniowy kurs Scala, gdy wcześniej potrzebowali tylko 1-tygodniowego kursu Java.
źródło
Myślę, że podstawowym problemem związanym z tą metodą jest to, że
(implicit bf : CanBuildFrom[Repr, B, That])
przebiega bez żadnego wyjaśnienia. Chociaż wiem, jakie są ukryte argumenty, nic nie wskazuje na to, jak wpływa to na połączenie. Ściganie się przez skaladok sprawia, że jestem bardziej zdezorientowany (kilka klas związanychCanBuildFrom
nawet z dokumentacją).Myślę, że proste „musi być ukryty obiekt w zasięgu,
bf
który zapewnia konstruktor dla obiektów typuB
do typu zwracanegoThat
”, nieco by pomógł, ale jest to dość solidna koncepcja, gdy wszystko, co naprawdę chcesz zrobić, to mapowaćA
doB
„s. W rzeczywistości nie jestem pewien, czy to prawda, ponieważ nie wiem, coRepr
oznacza ten typ , a dokumentacja naTraversable
pewno nie daje żadnych wskazówek.Pozostały mi więc dwie opcje, żadna z nich nie jest przyjemna:
Rozumiem, że Scala w gruncie rzeczy odsłania wnętrzności tego, jak te rzeczy działają, i że ostatecznie jest to sposób na robienie tego, co opisuje starorzecza. Ale to odwraca uwagę od podpisu.
źródło
Repr
jest odwracalną reprezentacją, tj.List
lubSet
lubMap
. Myślę, że jako ramy, jeśli zamierzasz zacząć przeglądać podpisy metod (zamiast tylko używać metod przez kopiowanie przykładów), musisz najpierw zrozumieć ogólny projekt. IMHO Scaladoc powinien być pełen przykładowego użyciaRepr
znaczy? Spodziewałbym się wyjaśnienia w skaladoku, ale tak naprawdę nie było to dla mnie oczywiste. Myślę, że jest to powszechny wzorzec w skaladocu (spójrz naActor.react
iActor.receive
- powiedziano mi i widziałem, że robią zupełnie inne rzeczy, ale ich skaladok jest identyczny).Jestem początkującym Scala i szczerze mówiąc, nie widzę problemu z tego typu sygnaturą. Ten parametr jest funkcją do mapowania, a domyślny parametr konstruktora, aby zwrócić poprawną kolekcję. Jasne i czytelne.
Właściwie to wszystko jest dość eleganckie. Parametry typu konstruktora pozwalają kompilatorowi wybrać właściwy typ zwracany, podczas gdy mechanizm parametru niejawnego ukrywa ten dodatkowy parametr przed użytkownikiem klasy. Próbowałem tego:
To polimorfizm zrobiony dobrze.
Oczywiście, nie jest to główny nurt i odstraszy wielu. Przyciągnie także wielu, którzy cenią jego wyrazistość i elegancję.
źródło
Niestety podpis, który podałeś, jest niepoprawny dla mapy i istnieje uzasadniona krytyka.
Pierwsza krytyka polega na tym, że podważając podpis mapy, mamy coś bardziej ogólnego. Powszechnym błędem jest przekonanie, że jest to domyślna zaleta. To nie jest Funkcja mapy jest bardzo dobrze zdefiniowana jako funktor kowariantny Fx -> (x -> y) -> Fy z zachowaniem dwóch praw składu i tożsamości. Wszystko inne, co przypisuje się „mapie”, to parodia.
Podany podpis jest czymś innym, ale nie jest mapą. Podejrzewam, że próbuje to być wyspecjalizowana i nieco zmieniona wersja podpisu „trawersowania” z gazety „Esencja wzoru iteratora”. Oto jego podpis:
Przekształcę go w Scalę:
Oczywiście, że zawodzi - to nie jest wystarczająco ogólne! Jest również nieco inny (zwróć uwagę, że mapę możesz uzyskać, biegając przez funktor tożsamości). Podejrzewam jednak, że gdyby twórcy bibliotek byli bardziej świadomi dobrze uogólnionych bibliotek uogólnień, które zostały dobrze udokumentowane (programowanie aplikacyjne z efektami poprzedza powyższe), to nie widzielibyśmy tego błędu.
Po drugie, funkcja mapy jest szczególnym przypadkiem w Scali ze względu na jej użycie w zrozumieniu. To niestety oznacza, że lepiej wyposażony projektant biblioteki nie może zignorować tego błędu bez poświęcenia składniowego cukru ze zrozumień. Innymi słowy, jeśli projektanci biblioteki Scala mieliby zniszczyć metodę, można to łatwo zignorować, ale proszę nie mapować!
Mam nadzieję, że ktoś o tym mówi, ponieważ w tej chwili będzie trudniej obejść błędy popełniane przez Scalę, najwyraźniej z powodów, które mam poważne zastrzeżenia. Oznacza to, że rozwiązaniem „nieodpowiedzialnych zastrzeżeń ze strony przeciętnego programisty (tj. Zbyt mocno!)” Nie jest „uspokojenie ich, aby im to ułatwić”, ale zamiast tego, dostarczenie wskazówek i pomocy, aby stać się lepszymi programistami. Cele siebie i Scali spierają się w tej sprawie, ale wracając do twojego punktu.
Prawdopodobnie miałeś rację, przewidując konkretne odpowiedzi od „przeciętnego programisty”. To znaczy ludzie, którzy twierdzą, „ale to jest zbyt skomplikowane!” lub niektóre takie. Są to Yegges lub Blochs, o których mówisz. Moja odpowiedź na te osoby z ruchu antyintelektualizmu / pragmatyzmu jest dość surowa i już spodziewam się szeregu odpowiedzi, więc pominę to.
Naprawdę mam nadzieję, że biblioteki Scali poprawią się, a przynajmniej błędy można bezpiecznie schować w kącie. Java to język, w którym „próba zrobienia czegoś pożytecznego” jest tak niewiarygodnie kosztowna, że często nie jest tego warta, ponieważ przytłaczającej liczby błędów po prostu nie da się uniknąć. Błagam Scalę, aby nie podążał tą samą ścieżką.
źródło
Całkowicie zgadzam się zarówno z pytaniem, jak i odpowiedzią Martina :). Nawet w Javie czytanie javadoc za pomocą generyków jest znacznie trudniejsze niż powinno być z powodu dodatkowego hałasu. Jest to złożone w Scali, gdzie niejawne parametry są używane, jak w przykładowym kodzie pytań (podczas gdy implikacje robią bardzo użyteczne rzeczy do modyfikowania kolekcji).
Nie sądzę, że jest to problem z językiem per se - myślę, że to bardziej kwestia narzędzi. I chociaż zgadzam się z tym, co mówi Jörg W Mittag, myślę, że patrząc na scaladoc (lub dokumentację typu w twoim IDE) - powinno to wymagać tak małej mocy mózgu, jak to możliwe, aby zrozumieć, co to jest metoda, co bierze i powraca. Nie powinno być potrzeby hakowania algebry na kawałku papieru, aby ją zdobyć :)
Na pewno IDE potrzebują fajnego sposobu na pokazanie wszystkich metod dla dowolnej zmiennej / wyrażenia / typu (który, podobnie jak w przykładzie Martina, może mieć wbudowane wszystkie ogólne, aby był miły i łatwy w użyciu). Podoba mi się też pomysł Martina, by domyślnie ukrywał implikacje.
Weźmy przykład w scaladoc ...
Patrząc na to w skaladoku, chciałbym, aby blok ogólny [B, That] był domyślnie ukryty, a także parametr niejawny (może pokazują, jeśli umieścisz małą ikonę za pomocą myszy) - jako dodatkowy element do grok czytanie tego, co zwykle nie jest tak istotne. np. wyobraź sobie, że to wyglądało ...
ładne, jasne i oczywiste, co robi. Możesz zastanawiać się, co to jest „To”, jeśli najedziesz myszką lub klikniesz, może rozwinąć tekst [B, That] podkreślający na przykład „To”.
Może może być użyta mała ikona dla deklaracji [] i (domyślnie ...) bloku, więc jest jasne, że małe części instrukcji są zwinięte? Trudno jest użyć do tego tokena, ale użyję. Na razie...
Tak więc domyślnie „szum” systemu typów jest ukryty przed 80% tego, na co ludzie powinni patrzeć - nazwa metody, typy parametrów i typ zwracany w przyjemny, prosty, zwięzły sposób - z niewielkimi rozszerzalnymi linkami do szczegółów jeśli tak bardzo cię to obchodzi.
Przeważnie ludzie czytają scaladoc, aby dowiedzieć się, jakie metody mogą wywołać dla typu i jakie parametry mogą przekazać. W pewnym sensie przeciążamy użytkowników zbyt szczegółami, tak jak IMHO.
Oto kolejny przykład ...
Teraz, jeśli ukryliśmy deklarację ogólną, jest łatwiejsza do odczytania
Następnie, gdy ludzie najeżdżają na kursor, powiedzmy, A1, moglibyśmy pokazać deklarację A1 jako A1 <: A. Typy kowariantne i przeciwwariantyczne w rodzajach generują również dużo hałasu, który moim zdaniem może być renderowany w znacznie łatwiejszy sposób.
źródło
Nie wiem, jak ci to przekazać, ale mam doktorat z Cambridge i używam 2.8 w porządku.
Mówiąc poważniej, prawie nie spędzałem czasu z wersją 2.7 (nie współpracuje z biblioteką Java, której używam) i zacząłem używać Scali nieco ponad miesiąc temu. Mam trochę doświadczenia z Haskellem (niewiele), ale po prostu zignorowałem rzeczy, którymi się martwisz, i szukałem metod, które pasowałyby do moich doświadczeń z Javą (których używam do życia).
A więc: Jestem „nowym użytkownikiem” i nie byłem zniechęcony - fakt, że działa jak Java, dał mi wystarczającą pewność siebie, aby zignorować fragmenty, których nie rozumiałem.
(Jednak powodem, dla którego patrzyłem na Scalę, było częściowo sprawdzenie, czy popchnąć ją w pracy, a ja jeszcze tego nie zrobię. Zmniejszenie zastraszania dokumentacji z pewnością by pomogło, ale zaskoczyło mnie to, jak bardzo jest nadal zmienianie się i rozwijanie (szczerze mówiąc, to, co mnie najbardziej zaskoczyło, było niesamowite, ale zmiany przyszły bardzo blisko). Myślę więc, że wolę raczej, aby ograniczone zasoby zostały w to włożone stan końcowy - nie sądzę, że spodziewali się, że będą tak popularni.)
źródło
W ogóle nie znam Scali, jednak kilka tygodni temu nie mogłem czytać Clojure. Teraz mogę przeczytać większość, ale nie mogę jeszcze napisać niczego poza najbardziej uproszczonymi przykładami . Podejrzewam, że Scala nie jest inna. Potrzebujesz dobrej książki lub kursu w zależności od tego, jak się uczysz. Właśnie czytając powyższą deklarację mapy , dostałem może 1/3.
Wierzę, że większymi problemami nie jest składnia tych języków, ale przyjęcie i internalizacja paradygmatów, które czynią je użytecznymi w codziennym kodzie produkcyjnym. Dla mnie Java nie była wielkim skokiem z C ++, który nie był wielkim skokiem z C, który wcale nie był skokiem z Pascala, ani Basic itp. ... Ale kodowanie w funkcjonalnym języku takim jak Clojure to ogromny skok (dla i tak). Myślę, że w Scali można kodować w stylu Java lub Scala. Ale w Clojure stworzysz niezły bałagan, starając się powstrzymać swoje przyzwyczajenia od Java.
źródło
Scala ma wiele szalonych funkcji (szczególnie w przypadku ukrytych parametrów), które wyglądają na bardzo skomplikowane i akademickie, ale zostały zaprojektowane tak, aby ułatwić obsługę. Najbardziej przydatne otrzymują cukier syntaktyczny (
[A <% B]
co oznacza, że obiekt typu A ma niejawną konwersję na obiekt typu B) i dobrze udokumentowane wyjaśnienie tego, co robią. Ale przez większość czasu, jako klient tych bibliotek, możesz zignorować ukryte parametry i zaufać im, że zrobią to dobrze.źródło
Nie sądzę, że jest to główny czynnik, który wpłynie na popularność Scali, ponieważ Scala ma dużo mocy, a jej składnia nie jest tak obca programistom Java / C ++ / PHP jak Haskell, OCaml, SML, Lisps, itp..
Sądzę jednak, że popularność Scali spadnie w mniejszym stopniu niż obecnie Java, ponieważ uważam również, że następny główny język musi być znacznie uproszczony, a jedynym sposobem, aby się tam dostać, jest czysta niezmienność, tj. Deklaratywna jak HTML, ale Turing jest kompletny . Jestem jednak stronniczy, ponieważ rozwijam taki język, ale uczyniłem to dopiero po kilkumiesięcznym badaniu, że Scala nie może wystarczyć na to, czego potrzebuję.
Nie sądzę, żeby reputacja Scali ucierpiała z powodu kompleksu Haskell. Ale myślę, że niektórzy odłożą naukę, ponieważ dla większości programistów nie widzę jeszcze przypadku użycia, który zmusiłby ich do korzystania ze Scali, i odłożą naukę o tym. Być może wysoce skalowalna strona serwera jest najbardziej przekonującym przypadkiem użycia.
A dla głównego nurtu rynku pierwsza nauka Scali nie jest „powiewem świeżego powietrza”, gdzie natychmiast pisze się programy, takie jak najpierw HTML lub Python. Scala ma tendencję do wyrastania na tobie, gdy ktoś pozna wszystkie szczegóły, na które się natkniesz od samego początku. Być może jednak, gdybym od początku czytał programowanie w Scali, moje doświadczenie i opinia na temat krzywej uczenia się byłyby inne.
Zdecydowanie.
Używam Scali jako początkowej platformy mojego nowego języka. Prawdopodobnie nie budowałbym kodu w bibliotece kolekcji Scali, gdybym inaczej używał Scali w celach komercyjnych. Chciałbym stworzyć własną bibliotekę opartą na teorii kategorii, ponieważ kiedy tylko spojrzałem, zauważyłem, że podpisy typu Scalaza są jeszcze bardziej szczegółowe i nieporęczne niż biblioteka kolekcji Scali. Częścią tego problemu może być sposób implementacji klas typów przez Scalę, i to jest niewielki powód, dla którego tworzę własny język.
Postanowiłem napisać tę odpowiedź, ponieważ chciałem zmusić się do zbadania i porównania projektu klasy kolekcji Scali z tym, który robię dla mojego języka. Równie dobrze mogę podzielić mój proces myślowy.
Wykorzystanie abstrakcyjne konstruktora w kolekcjach 2.8 Scala jest rozsądną zasadą projektowania. Chcę zbadać dwa kompromisy projektowe poniżej.
KOD TYLKO DO PISANIA : Po napisaniu tego rozdziału przeczytałem komentarz Carla Smotricza, który zgadza się z tym, co według mnie będzie kompromisem. Komentarze Jamesa Strachana i davetron5000 są zgodne, że znaczenie tego (to nie jest nawet że [B]) i mechanizmu ukrytego nie jest łatwe do zrozumienia intuicyjnie. Zobacz moje użycie monoidu w numerze 2 poniżej, który moim zdaniem jest znacznie bardziej wyraźny. Komentarz Dereka Mahara dotyczy pisania Scali, ale co z czytaniem Scali innych osób, co nie jest „w typowych przypadkach”.
Jedna krytyka, którą przeczytałem o Scali, polega na tym, że łatwiej jest ją napisać niż przeczytać kod napisany przez innych. I okazuje się, że jest to czasami prawdą z różnych powodów (np. Wiele sposobów pisania funkcji, automatyczne zamykanie, jednostka DSL itp.), Ale nie jestem zdecydowany, czy jest to istotny czynnik. Tutaj użycie niejawnych parametrów funkcji ma plusy i minusy. Z drugiej strony, zmniejsza gadatliwość i automatyzuje wybór obiektu konstruktora. W przykładzie Oderskiegokonwersja z BitSet, tj. Set [Int], na Set [String] jest niejawna. Nieznany czytelnik kodu może nie wiedzieć, jaki jest typ kolekcji, chyba że może dobrze uzasadnić wszystkie potencjalne niewidzialne potencjalne niejawne konstruktory, które mogą istnieć w bieżącym zakresie pakietu. Oczywiście doświadczony programista i autor kodu będzie wiedział, że BitSet jest ograniczony do Int, dlatego mapa na String musi zostać przekonwertowana na inny typ kolekcji. Ale jaki typ kolekcji? Nie jest to wyraźnie określone.
PROJEKTOWANIE KOLEKCJI AD-HOC: Po napisaniu tego rozdziału przeczytałem komentarz Tony'ego Morrisa i zdałem sobie sprawę, że robię to samo. Być może moja bardziej szczegółowa prezentacja wyjaśni sprawę.
W „Fighting Bit Rot with Types” Odersky & Moors przedstawiono dwa przypadki użycia. Są one ograniczeniem BitSet do elementów Int i Map do parowania elementów krotkowych i są podane jako powód, dla którego ogólna funkcja mapowania elementów, A => B, musi być w stanie zbudować alternatywne typy kolekcji miejsc docelowych. Jednak afaik jest to wadliwe z perspektywy teorii kategorii. Aby zachować spójność w teorii kategorii i tym samym uniknąć przypadków narożnych, te typy kolekcji są funktorami, w których każdy morfizm, A => B, musi być odwzorowany między obiektami w tej samej kategorii funktorów, Lista [A] => Lista [B], BitSet [A] => BitSet [B]. Na przykład Opcja to funktor, który można przeglądać jako zbiór zestawów jednego Some (obiektu) i None. Nie ma ogólnej mapy od Opcji Brak lub Brak Listy do innych funktorów, które nie „
Dokonano tutaj wyboru kompromisu. W bibliotece nowego zbioru do projektowania kolekcji postanowiłem uczynić wszystko funktorem, co oznacza, że jeśli zaimplementuję BitSet, musi on obsługiwać wszystkie typy elementów, wykorzystując wewnętrzną reprezentację pola niebitowego, gdy jest prezentowany inny niż parametr typu liczba całkowita, a ta funkcja jest już w zestawie, który dziedziczy w Scali. A w moim projekcie Map musi mapować tylko jego wartości i może zapewnić osobną metodę niefunkcjonalną do mapowania krotek pary (klucz, wartość). Jedną zaletą jest to, że każdy funktor jest wtedy zwykle również aplikacją, a może i monadą. Zatem wszystkie funkcje między typami elementów, np. A => B => C => D => ..., są automatycznie podnoszone do funkcji między podniesionymi typami aplikacji, np. Lista [A] => Lista [B] => Lista [ C] => Lista [D] => .... Do mapowania z funktora na inną klasę kolekcji oferuję przeciążenie mapy, które przyjmuje monoid, np. Zero, brak, 0, „”, Array () itp. Tak więc funkcja abstrakcji konstruktora jest metodą dołączania monoidu i jest dostarczany jawnie jako niezbędny parametr wejściowy, a więc bez niewidocznych niejawnych konwersji. (Tangens: ten parametr wejściowy umożliwia także dołączanie do niepustych monoidów, czego projekt mapy Scali nie jest w stanie wykonać). Takie konwersje są mapą i fałdem w tym samym przebiegu iteracji. Zapewniam także możliwość przejścia, w sensie kategorii, „Programowanie aplikacji z efektami” McBride & Patterson, która umożliwia także składanie map + w jednym przejściu iteracyjnym z dowolnego przejścia do dowolnej aplikacji, gdzie większość każdej klasy kolekcji jest jednocześnie.
Tak więc afaiki kolekcje Scali są „ad-hoc” w tym sensie, że nie są ugruntowane w teorii kategorii, a teoria kategorii jest esencją semantyki denotacyjnej wyższego poziomu. Chociaż niejawne budulce Scali są na pierwszy rzut oka „bardziej uogólnione” niż model funktora + konstruktor monoidów + możliwy do przejścia -> aplikacja, nie udowodniono, że są spójne z jakąkolwiek kategorią, a zatem nie wiemy, jakie reguły stosują w najbardziej ogólny sens i podane przypadki narożne mogą nie być zgodne z żadnym modelem kategorii. Po prostu nie jest prawdą, że dodanie większej liczby zmiennych czyni coś bardziej ogólnym, a była to jedna z ogromnych zalet teorii kategorii, ponieważ zapewnia reguły, dzięki którym można zachować ogólność, podnosząc jednocześnie semantykę wyższego poziomu. Kolekcja jest kategorią.
Czytałem gdzieś, myślę, że był to Odersky, ponieważ innym uzasadnieniem dla projektu biblioteki jest to, że programowanie w czysto funkcjonalnym stylu ma koszt ograniczonej rekurencji i szybkości, w której rekursja ogona nie jest używana. Nie miałem trudności z zastosowaniem rekurencji ogona w każdym napotkanym do tej pory przypadku.
Dodatkowo mam w głowie niekompletny pogląd, że niektóre kompromisy Scali wynikają z tego, że staram się być zarówno językiem zmiennym, jak i niezmiennym, w przeciwieństwie na przykład do języka Haskell lub języka, który rozwijam. Jest to zgodne z komentarzem Tony'ego Morrisa dotyczącym zrozumienia. W moim języku nie ma pętli ani modyfikowalnych konstrukcji. Mój język będzie się opierał na Scali (na razie) i wiele mu zawdzięcza, a nie byłoby to możliwe, gdyby Scala nie miała ogólnego systemu typów i zmienności. To może nie być prawda, ponieważ uważam, że Odersky & Moors („Walcząca zgnilizna bitów z typami”) nie zgadza się z twierdzeniem, że Scala jest jedynym językiem OOP z wyższymi rodzajami, ponieważ zweryfikowałem (ja i przez Boba Harpera) ten standard ML je ma. Wydaje się również, że system typów SML może być równoważnie elastyczny (od lat 80.), co może nie być łatwo docenione, ponieważ składnia nie jest tak bardzo podobna do Java (i C ++ / PHP) jak Scala. W każdym razie nie jest to krytyka Scali, ale próba przedstawienia niepełnej analizy kompromisów, co mam nadzieję ma związek z tym pytaniem. Scala i SML nie cierpią z powodu niemożności zrobienia tego przez Haskellawielokrotne dziedziczenie diamentów , co jest krytyczne i rozumiem, dlaczego tak wiele funkcji w Preludium Haskell powtarza się dla różnych typów.
źródło
Konieczne wydaje się tutaj podanie stopnia: licencjat z nauk politycznych i licencjat z informatyki.
Do momentu:
Scala jest trudna, ponieważ jej podstawowy paradygmat programowania jest trudny. Programowanie funkcjonalne przeraża wiele osób. Możliwe jest budowanie zamknięć w PHP, ale ludzie rzadko to robią. Więc nie, nie ten podpis, ale cała reszta zniechęci ludzi, jeśli nie będą mieli odpowiedniego wykształcenia, aby docenić siłę leżącą u podstaw paradygmatu.
Jeśli ta edukacja jest dostępna, każdy może to zrobić. W zeszłym roku buduję komputer szachy z grupą dzieci w szkole w SCALA! Mieli swoje problemy, ale w końcu sobie poradzili.
Nie martwiłbym się.
źródło
Mam też dyplom z matematyki z Oksfordu! Zajęło mi trochę czasu, aby „zdobyć” nowe kolekcje. Ale teraz bardzo to lubię. W rzeczywistości pisanie „map” było jedną z pierwszych dużych rzeczy, które wpędziły mnie w błąd w wersji 2.7 (być może odkąd pierwszą rzeczą, którą zrobiłem, była podklasa jednej z klas kolekcji).
Czytanie artykułu Martina na temat nowych kolekcji 2.8 naprawdę pomogło wyjaśnić zastosowanie implicitów, ale tak, sama dokumentacja zdecydowanie musi lepiej wykonać wyjaśnienie roli różnego rodzaju implicitów w sygnaturach metod kluczowych API.
Moim głównym zmartwieniem jest więcej: kiedy zostanie wydana wersja 2.8? Kiedy raporty o błędach przestaną się pojawiać? Czy zespół Scala odgryzł więcej niż mógł żuć 2.8 / Próbował zmienić zbyt wiele na raz?
Naprawdę chciałbym, aby wersja 2.8 została ustabilizowana do wydania jako priorytet przed dodaniem czegoś nowego w ogóle i zastanawiam się (podczas oglądania z boku), czy można wprowadzić pewne ulepszenia w sposobie zarządzania planem rozwoju kompilatora Scala.
źródło
Co z komunikatami o błędach w użyciu witryny?
A jeśli chodzi o przypadek użycia, należy zintegrować istniejące typy z niestandardowymi, które pasują do DSL. Trzeba być dobrze wykształconym w kwestiach asocjacji, pierwszeństwa, ukrytych konwersji, ukrytych parametrów, wyższych rodzajów i być może typów egzystencjalnych.
Dobrze wiedzieć, że w większości jest to proste, ale niekoniecznie wystarczające. Przynajmniej jeden facet zna te rzeczy, jeśli ma być zaprojektowana szeroka biblioteka.
źródło