Czy biblioteka zbiorów Scala 2.8 jest przykładem „najdłuższej notatki samobójczej w historii”? [Zamknięte]


873

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.


10
fud oznacza po prostu strach, niepewność i wątpliwości - myślę, że dość wyraźnie wyraża ton wypowiedzi Josha Blocha, który również zgadzam się z tym, że jest dobrze uzasadniony i uzasadniony itp. Jeśli widzisz zmiany, pierwotnie nie umieściłem fud, ponieważ Nie chciałem sugerować -ve konotacji
oxbow_lakes

32
Pytanie to zostało wspomniane w rozmowie otwierającej Martina Oderskiego podczas Dni Scali 2010 dni2010.scala-lang.org/node/136
Binil Thomas

7
W Scali uwielbiam to, że nie musisz rozumieć, że jest to złożony system do robienia prostych i eleganckich rzeczy. jego składnia może być zniechęcająca, ale zapewnia jedną rzecz, nie ma „magii”, np. magia jest częścią języka, myślę, że jest to bardzo odważne i inteligentne podejście, masz język, który może tworzyć nowe DSL i nowe mini języki same w sobie, tak, niewłaściwymi rękami Scala może być bardzo dobrym dodatkiem do twojej włoskiej kolacji, ale gdy się przyzwyczaisz, jest to niesamowity język
Eran Medan

87
Jak to pytanie może być „mało konstruktywne”, skoro doprowadziło @MartinOdersky do ponownej oceny użyteczności Scali i ukrycia systemu dokumentacji szczegółów systemu, nie wspominając o pouczającej dyskusji?
Jerry101

14
Rzeczywiście, SO dotyczy tylko techniki o właściwym formacie. Jeśli masz coś delikatnego, intrygującego i dalekosiężnego, zajrzyj gdzie indziej. Niech żyje biurokratyczna mentalność.
qed

Odpowiedzi:


892

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 maplub collectbył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ść mapobsługiwana przez jego skomplikowany typ jest dość zaawansowana. Rozważ to:

scala> import collection.immutable.BitSet
import collection.immutable.BitSet

scala> val bits = BitSet(1, 2, 3)
bits: scala.collection.immutable.BitSet = BitSet(1, 2, 3)

scala> val shifted = bits map { _ + 1 }
shifted: scala.collection.immutable.BitSet = BitSet(2, 3, 4)

scala> val displayed = bits map { _.toString + "!" }
displayed: scala.collection.immutable.Set[java.lang.String] = Set(1!, 2!, 3!)

Zobacz, jak zawsze dostajesz najlepszy możliwy typ? Jeśli zamapujesz Ints na Ints, otrzymasz ponownie a BitSet, ale jeśli zmapujesz Ints na Strings, otrzymasz generała Set. 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ła mapw BitSetDostała:

map(f: Int => Int): BitSet     (click here for more general type)

Dokumenty nie leżą w takim przypadku, ponieważ z perspektywy użytkownika mapa rzeczywiście ma taki typ (Int => Int) => BitSet. Ale mapma 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.


107
Czuję się jak niegrzeczny uczeń! Bardzo dziękuję za poświęcenie czasu na odpowiedź. Myślę, że bilans odpowiedzi pokazał mi, że nie muszę się martwić; będzie wystarczająco dużo ludzi, którzy w ogóle nie będą zastraszani.
oxbow_lakes

164
Nie, myślę, że miałeś całkowitą rację, trafiając w tę kwestię. I inni będą się bać, chyba że coś z tym zrobimy.
Martin Odersky,

33
Martin, podoba mi się twoja sugestia, aby pokazać uproszczoną sygnaturę metody i ukryć ogólne szczegóły za linkiem.
Derek Mahar

18
Myślę, że rozwiązaniem, które równie dobrze by działało, jest więcej wyjaśnień w dokumentacji. Nie uznałbym podpisów za tak zastraszające, gdyby nie fakt, że większość metod (a nawet większość klas) nie ma więcej niż jednego zdania opisującego ich cel i działanie.
Nick Johnson

98
Aktualizacja: Ostatnia wersja Scali 2.8 ma mechanizm podobny do tego, który opisałem. Jeśli spojrzysz na BitSet w skaladokach, znajdziesz: def map [B] (f: (Int) ⇒ B): BitSet [B] [przypadek użycia] Buduje nową kolekcję poprzez zastosowanie funkcji do wszystkich elementów tego zestawu bitów.
Martin Odersky

226

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 mapopublikowanej funkcji. Wygląda mi na prawie taki sam podpis, jak mapw 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 argumentu IterableLike, 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 mapnie musi być listą, uporządkowana, sortowalna ani nic podobnego. Jedyną rzeczą, na której mapzależ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

map :: (a → b)[a][b]

który jest tradycyjnym typem podpisu map, uogólniono go, aby nie wymagał konkretnej, Lista jedynie IterableLikestruktury danych

map :: (IterableLike i, IterableLike j)(a → b) → i → j

któ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:

map :: IterableLike i ⇒ (a → b) → i → ([b] → c) → c

Przyznaję, że składnia jest nieco dziwniejsza, ale semantyka jest taka sama. Zasadniczo zaczyna się od

def map[B](f: (A) ⇒ B): List[B]

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 konkretnego Listna bardziej ogólnyIterableLike

def map[B](f: (A) ⇒ B): IterableLike[B]

Teraz zastępuje IterableLikekolekcję wyników funkcją, która generuje , właściwie, właściwie wszystko.

def map[B, That](f: A ⇒ B)(implicit bf: CanBuildFrom[Repr, B, That]): That

W co naprawdę wierzę, nie jest to takie trudne do zrozumienia. Tak naprawdę potrzebujesz tylko kilku narzędzi intelektualnych:

  1. Musisz wiedzieć (z grubsza), co mapjest. Przyznaję, że gdybyś podał tylko podpis typu bez nazwy metody, znacznie trudniej byłoby ustalić, co się dzieje. Ale skoro już wiesz, co mapnależy zrobić i wiesz, jaki powinien być podpis typu, możesz szybko zeskanować podpis i skupić się na anomaliach, na przykład „dlaczego mapbierze to dwie funkcje za argument, a nie jedną?”.
  2. Musisz być w stanie odczytać podpis typu. Ale nawet jeśli nigdy wcześniej nie widziałeś Scali, powinno to być dość łatwe, ponieważ tak naprawdę jest to tylko mieszanka składni typów, które znasz już z innych języków: VB.NET używa nawiasów kwadratowych do polimorfizmu parametrycznego i używa strzałki do oznaczenia zwracany typ i dwukropek do oddzielenia nazwy i typu są w rzeczywistości normą.
  3. Musisz z grubsza wiedzieć, na czym polega programowanie ogólne. (Co nie jest , że trudno zorientować się, ponieważ jest to w zasadzie wszystko napisane w imieniu: to dosłownie programowanie w sposób ogólny).

Żadna z tych trzech nie powinna sprawić poważnego bólu głowy żadnemu profesjonalnemu, a nawet hobbystycznemu programistowi. mapbył 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.


36
@Jorg - to niesamowita odpowiedź; Dziękuję Ci. Niezależnie od tego, czy masz stopień naukowy, czy nie, jesteś jaśniejszym człowiekiem niż ja. Jedyne, co mam wątpliwości, to to, że rozumiem szeroki obraz tego, co dzieje się w sygnaturze metody. Jednak szczegóły są nadal mylące: w jaki sposób Thatwnioskowanie i powiązanie z typem Bjest 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!
oxbow_lakes

50
Ładne wyjaśnienie, ale jeszcze bardziej przekonałeś mnie, że podpis „Scala 2.8” metody mapy jest bardzo skomplikowany.
Derek Mahar

11
Język, który wygląda tak: def map [B] (f: (A) ⇒ B): IterableLike [B] jest znacznie bardziej zachęcający niż ten, który wygląda tak: def map [B, That] (f: A ⇒ B ) (domyślnie bf: CanBuildFrom [Repr, B, That]): That
Mark Essel

215
Uważam, że to całkiem interesujące, że zaczynasz od twierdzenia, że ​​znasz tylko podstawowy, rubinowy i smalltalk, i kontynuując, że nie masz wykształcenia akademickiego w tej dziedzinie. ... a następnie twierdząc, że ma wiedzę na temat złożoności systemów typów w językach takich jak Miranda i Clean; języki najczęściej znane tylko wśród poważnych maniaków programowania i naukowców.
Sami,

14
Masz rację, że porównanie z Haskellem jest niepoprawne w tym, że „mapa :: (a -> b) -> [a] -> [b]” jest specyficzna dla list. Jednak wersja uogólniona, wersja klasy Functor, jest wciąż znacznie prostsza niż wersja Scala: klasa Functor f gdzie fmap :: (a -> b) -> fa -> fb
Orclev

175

To samo w C ++ :

template <template <class, class> class C,
          class T,
          class A,
          class T_return,
          class T_arg
              >
C<T_return, typename A::rebind<T_return>::other>
map(C<T, A> &c,T_return(*func)(T_arg) )
{
    C<T_return, typename A::rebind<T_return>::other> res;
    for ( C<T,A>::iterator it=c.begin() ; it != c.end(); it++ ){
        res.push_back(func(*it));
    }
    return res;
}

105
... i mówią, że Scala jest niejasna. Hه!
missingfaktor

24
Wyobraź sobie, jak by to wyglądało, gdyby zamiast arbitralnych wielkich liter zastosowano właściwe samoopisujące identyfikatory. :-)
Ti Strga

14
Przydatne jest zobaczenie tego porównania, ale byłoby bardziej sprawiedliwe, gdyby pominięto wdrożenie.
Aaron Novstrup,

2
Nie jestem wielkim fanem wskaźnika funkcji obowiązkowej. Oczywiście typ funcpowinien być parametrem szablonu, a powinieneś użyć result_ofi, is_callableaby uzyskać inne typy i odpowiednio ograniczyć zestaw przeciążeń :-)
Kerrek SB,

1
bolą mnie oczy !!!
Ashkan Kh. Nazary

71

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:

  1. 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.

  2. 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.

  3. 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.

  4. 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.


10
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.
gamliela

9
@ Gamliela, nie sądzę, że będziemy z tego powodu smutni. Wiedza ma zawsze więcej niż jeden poziom do zastosowania, a praca i zaufanie innych (recenzowane) w dowolnym systemie mogą zawsze być wykorzystane, tak jak używamy arytmetyki codziennie i całkowicie ignorujemy przerażające algebry działające za nią.
lcn

55

Czy to zniechęci ludzi do Scali?

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.

Czy to nada Scali złą sławę w świecie komercyjnym jako akademicka gra, którą mogą zrozumieć tylko oddani doktoranci? Czy CTO i szefowie oprogramowania będą się odstraszyć?

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.

Czy przeprojektowanie biblioteki było rozsądnym pomysłem?

Absolutnie. Sprawia, że ​​kolekcje są znacznie lepiej dopasowane do reszty języka i systemu czcionek, nawet jeśli nadal mają ostre krawędzie.

Jeśli używasz Scala w celach komercyjnych, martwisz się tym? Czy planujesz od razu zastosować 2.8 lub poczekać, aby zobaczyć, co się stanie?

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.


31
„zapobiegnie to również odkładaniu ludzi”. to. absolutnie. scala jest pierwszym językiem, który sprawia, że ​​inżynieria z czymś porównywalnym do haskell (w sile systemu typów) jest dla wielu z nas możliwa. nie ma żadnego cholernego sposobu, w jaki mógłbym przekonać pracę do korzystania z haskell, ale Scala naprawdę ma szansę i za to uwielbiam ją i spróbuję (jeśli uważam, że ma to sens) spróbować ją przyjąć, lub przynajmniej zaakceptować, w pracy.
Andrew Cooke

+1 ode mnie też. Biorąc pod uwagę założenie, że Scala kładzie większy nacisk na głębię językową i rygor niż przystępność masową, odpowiedzi te są idealnie dopasowane.
Carl Smotricz

16
„Jutro programiści głównego nurtu będą używać języka, który jest używany przez najbardziej udanych programistów nowych aplikacji”. +1. Wspaniale powiedziane.
Vasil Remeniuk

46

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.


43

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, że Intnie 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.


9
Przepraszam za wszystkie komentarze. 1 tydzień to żart dla praktycznie każdego języka, ale to nie przeszkadza menedżerom w realizacji tego żartu. Kiedyś dostałem 3 dni na „przeszkolenie” grupy programistów C ++ w Javie. Poprosiłem o 5 dni, ale zwarłem się z powodów budżetowych.
Carl Smotricz

22
Do mojej pierwszej pracy dostałem książkę C ++ pod koniec rozmowy, aby dowiedzieć się, zanim zacznę pracę w poniedziałek. Jesteście wredni.
Tom Hawtin - tackline

12
@Tom @Erik Wy, chłopcy, macie łatwość. Dostałem schematy połączeń do komputera (wtedy nie było procesora) i powiedziałem, że mam dwie godziny na naprawienie błędu jako wywiad.
Daniel C. Sobral

33
@Daniel @Tom @Erik Kiedyś dostałem 0 i 1 i poprosiłem o użycie ich do rozwiązania problemu plecaka w czasie liniowym podczas wywiadu. Dałem mu szansę, ale niestety miałem tylko czas na stworzenie Eclipse (które, jak podejrzewam, można sprowadzić do plecaka). #tall_tale
Alex Miller

10
@Alex To pokazuje brak wyobraźni. Umieść jedno duże zero po lewej stronie, a dwa inne mniejsze zera po jego prawej stronie: jeden nad drugim, górny nieco po lewej. Umieść jeden między tymi dwoma mniejszymi zerami, przechodząc od lewej dolnej do prawej górnej. Powiedz, że to szansa na rozwiązanie plecaka w czasie liniowym. Gotowe. :-) +1 za zrównanie Eclipse i Plecaka. :-)
Daniel C. Sobral

33

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ązanych CanBuildFromnawet z dokumentacją).

Myślę, że proste „musi być ukryty obiekt w zasięgu, bfktóry zapewnia konstruktor dla obiektów typu Bdo typu zwracanego That”, nieco by pomógł, ale jest to dość solidna koncepcja, gdy wszystko, co naprawdę chcesz zrobić, to mapować Ado B„s. W rzeczywistości nie jestem pewien, czy to prawda, ponieważ nie wiem, co Reproznacza ten typ , a dokumentacja na Traversablepewno nie daje żadnych wskazówek.

Pozostały mi więc dwie opcje, żadna z nich nie jest przyjemna:

  • Załóżmy, że zadziała to, jak działa stara mapa i jak działa mapa w większości innych języków
  • Zanurz się jeszcze trochę w kodzie źródłowym

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.


2
Reprjest odwracalną reprezentacją, tj. Listlub Setlub Map. 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życia
oxbow_lakes

10
Jak więc ustaliłbym, co to Reprznaczy? 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 na Actor.reacti Actor.receive- powiedziano mi i widziałem, że robią zupełnie inne rzeczy, ale ich skaladok jest identyczny).
davetron5000,

7
Zgadzam się z davetron5000. Znam Scalę, ale niejawne definicje wciąż powodują ból głowy. Przyczyna nie jest sama w sobie domniemana, ale sposób ich użycia. Zdecydowanie powinna istnieć lepsza obsługa dokumentacji i narzędzi do zrozumienia typów Scala. To powiedziawszy, myślę, że system typów naprawdę ma coś ważnego do zaoferowania. Ale wciąż jesteśmy dopiero na początku rozsądnego programowania.
egaga

22

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:

Map(1 -> "a", 2 -> "b").map((t) => (t._2) -> (t._1)) // returns Map("a" -> 1, "b" -> 2)
Map(1 -> "a", 2 -> "b").map((t) =>  t._2)            // returns List("a", "b")

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ę.


20

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:

traverse :: (Traversable t, Applicative f) => (a -> f b) -> t a -> f (t b)

Przekształcę go w Scalę:

def traverse[A, B](f: A => F[B], a: T[A])(implicit t: Traversable[T], ap: Applicative[F]): F[T[B]

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ą.


3
Cześć Tony - dziękuję za twój przemyślany wkład tutaj. Udzieliłbym na to 2 odpowiedzi. Po pierwsze, nie wspomniałem o „przeciętnym programatorze” i nie wierzę, że Scala jest koniecznie do niego skierowana. Bez względu na to, czy jest to moje, czy też inne, uważam, że jestem powyżej średniej; jednak nadal uważam, że podpis typu jest zniechęcający! Innymi słowy, martwię się, że ponadprzeciętni programiści, rynek docelowy Scali, mogą zostać wypchnięci.
oxbow_lakes

6
Drugą kwestią jest to, że zasadniczo nie zgadzam się z tobą co do tego, czym jest Scala: Scala jest językiem pragmatycznym, a nie teoretycznie czystym. Dlaczego inaczej miałby być zaprojektowany na szczycie JVM? Jest to czysto pragmatyczna decyzja - jest skierowana do deweloperów „w prawdziwym świecie” - wybór, który mógł wymagać kompromisów! Zauważ też, że Bloch i Yegge są dalekie od przeciętnych programistów - ale o to mi chodzi. Nawet bardzo szanowani i inteligentni ludzie mogą mieć opinie na temat złożoności i czystości, które różnią się od twojej. Niestety, mają one również duży wpływ.
oxbow_lakes

3
Witaj oxbow_lakes, Celem firmy Scala jest uspokojenie typowych programistów, nawet kosztem dokładności i praktyczności. Ponadprzeciętni programiści są wypędzani (mam kilka anegdot), ale nie dlatego, że sygnatury typów są zniechęcające, ale z powodu natury niektórych błędów. Nie powiedziałem, że Scala jest pragmatyczny lub teoretyczny. Co więcej, nawet nie popieram (powszechnego?) Poglądu, że taka dychotomia istnieje. Biblioteki Scala wkręciły podpis mapy. Od lat pracuję nad błędami Scali; szczególnie biblioteki. Czas to zrobić ponownie.
Tony Morris,

5
Nie uważam Blocha ani Yegge za bardzo szanowanych i inteligentnych, ale w rzeczywistości mają one duży wpływ. Tak, to niefortunne.
Tony Morris,

9
Dlaczego odnosisz trawers do rozszerzonego podpisu Scali? Mapa Scali dla monofunkcji jest standardową mapą fmap. Ale ani BitSet, ani Map [A, B] nie są monofunkcjami, ale mapa ma na nich sensowną definicję. Taka jest motywacja podpisu Scali, a trawers nie rozwiązuje tego problemu. Dlaczego ogólność jest złą rzeczą? Funktory aplikacyjne śledzą efekty, jaki jest ich sens w Scali? Wreszcie, wierzę, że ogólną mapę Scali można wdrożyć w postaci uogólnionego trawersu, akceptując CanBuildFrom i zwracając potencjalnie inny Trawersowalny: nie trzeba poświęcać się dla zrozumienia!
Blaisorblade

15

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 ...

def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Repr, B, That]): That

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 ...

def map(f: A => B): That

ł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...

def map.(f: A => B).: That

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 ...

def orElse[A1 <: A, B1 >: B](that: PartialFunction[A1, B1]): PartialFunction[A1, B1]

Teraz, jeśli ukryliśmy deklarację ogólną, jest łatwiejsza do odczytania

def orElse(that: PartialFunction[A1, B1]): PartialFunction[A1, B1]

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.


5
Ale co oznacza „To” jako typ wyniku?
Blaisorblade

11

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.)


22
Myślę, że chce wiedzieć, czy osoby bez doktoratów z Cambridge poradzą sobie ze Scalą 2.8.
Ken Bloom

2
Haha: touche! Cóż, powiedziałem, że Scala 2.8 jest łatwa w użyciu - moje pytanie dotyczyło raczej tego, jak wyglądałby ktoś przeglądający interfejs API, aby zobaczyć, czy mu się podoba, zakładając, że nie miał wcześniejszego doświadczenia w Scali.
oxbow_lakes

1
@andrew - z wyglądu witryny yout ( acooke.org ) nie czujesz się niekomfortowo z zastraszającymi wizualnie koncepcjami
oxbow_lakes

Każdy, kto zajmuje się programowaniem w Malbolge, nawet jeśli jest to „tylko” Hello World, raczej nie jest zastraszany przez cokolwiek.
Carl Smotricz

10

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.


5
Nigdy nie chodzi o notację (ani nigdy więcej niż, powiedzmy, 10-15% o notacji), zawsze chodzi o pojęcia. A jeśli jesteś rozsądnie inteligentny i nie pochłonął cię dziesięciolecia wiedzy z różnych, być może sprzecznych modeli (jak zapewne jestem), wtedy zwykle nie jest zbyt trudno uchwycić te rzeczy. Ale jeśli jesteś zanurzony w jednym sposobie myślenia i robienia rzeczy, to jest co najmniej trochę wysiłku, aby się przystosować i wielu reaguje na takie zmiany. To tylko ludzka psychologia / natura. (Zastanawiam się, jak psychologia programowania komputerowego Weinberga wytrzymuje po prawie 40 latach?)
Randall Schulz

1
@Randall Schultz i Jeff G: Składnia / notacja jest rozsądnie łatwa dla osoby inteligentnej. Zasadniczo różne nazwy dla tych samych pojęć. Przyspieszenie w nowym języku to tylko kwestia praktyki. JEDNAK krok od programowania proceduralnego do programowania funkcjonalnego jest ... przerażająco szeroki. To naprawdę inny sposób myślenia. Rozmawiałem z Clojure od kilku miesięcy i uważam, że jest to stosunkowo „łatwy”, przyjemny język FP. Ale wciąż potrzebuję nadmiernej ilości czasu, aby znaleźć rzeczy, które byłyby proste w programowaniu proceduralnym.
Carl Smotricz

7

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.


Tak, składnia widoku przyspiesza zrozumienie.
egaga

6

Czy to zniechęci ludzi do Scali?

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ę.

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ć?

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.

Czy przeprojektowanie biblioteki było rozsądnym pomysłem?

Zdecydowanie.

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?

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.

  1. 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.

  2. 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.


Czy twój język będzie zorientowany obiektowo?
missingfaktor,

Tak, dziedziczy system czcionek Scali. Jednym z kluczowych rozróżnień jest to, że cecha jest podzielona na interfejs i mixin, gdzie interfejs zawiera tylko sygnatury metod i brak implementacji. I tylko interfejs może być określony jako typ. Implikacje są eliminowane, a klasy typów są obsługiwane w interfejsie SPOT. Oto przybliżony szkic szczegółów. Współpracownicy są mile widziani. Trochę kodu do biblioteki jest tutaj . To praca w toku, przepraszamy za wzmiankę o vaporware. Po prostu dzielę się przemyśleniami.
Shelby Moore III

5

Konieczne wydaje się tutaj podanie stopnia: licencjat z nauk politycznych i licencjat z informatyki.

Do momentu:

Czy to zniechęci ludzi do Scali?

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.

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?

Nie martwiłbym się.


4

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.


-1

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.


Ale jednym z głównych punktów jest różnica między biblioteką z perspektywy użytkownika i twórców. Oczywiście twórcy potrzebują imponującego zrozumienia wymaganych funkcji językowych (np. Typy wyższego rodzaju, ukryte pierwszeństwo) - pytanie brzmi: „czy użytkownicy?”
oxbow_lakes
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.