Podobne pytanie zostało zamknięte w sprawie SO.
Czasami podczas programowania stwierdzamy, że jakaś szczególna struktura sterowania byłaby dla nas bardzo przydatna, ale nie jest bezpośrednio dostępna w naszym języku programowania.
Jakie alternatywne struktury kontroli uważasz za użyteczny sposób organizowania obliczeń?
Celem jest tutaj znalezienie nowych sposobów myślenia o strukturze kodu, aby poprawić dzielenie na fragmenty i rozumowanie.
Możesz utworzyć składnię życzeniową / semantyczną, która jest obecnie niedostępna, lub przytoczyć mniej znaną strukturę sterowania w istniejącym języku programowania.
Odpowiedzi powinny dać pomysły na nowy język programowania lub ulepszenie rzeczywistego języka.
Pomyśl o tym jak o burzy mózgów, więc opublikuj coś, co Twoim zdaniem jest szalonym pomysłem, ale może być wykonalne w niektórych sytuacjach.
Chodzi o programowanie imperatywne.
Odpowiedzi:
OK, to zabawne pytanie.
Chciałbym też mieć generała
else
na chwilę i na pętle, bo gdy warunek nie jest spełniony przy pierwszym teście:Pozwala to uniknąć niewygodnego ponownego obliczania warunku lub przechowywania go w zmiennej.
źródło
while ... else
konstrukcji w sposób opisany przez Macneila w PHP. Myślę, że to świetny pomysł, ponieważ „oto wyniki / wyników nie było” jest dość powszechnym idiomem w aplikacjach internetowych.Dlaczego nie połączyć kilku odpowiedzi w jedną?
Rozszerzalna, uogólniona składnia konstrukcji kontroli przepływu w języku imperatywnym byłaby raczej przydatna i zabawna. Dopóki się to nie pojawi, domyślam się, że użyję Lisp lub czegoś takiego.
źródło
seventh { ... }
również.Struktury sterowania jako funkcje.
Chcę
for
,if
,else
,while
, etc być funkcje, nie specjalne konstrukcje.Chcę
return
,try/except
igoto
być pochodne kontynuacje.Ma to oczywiście mniej wspólnego z określoną strukturą kontroli, a więcej z tym, jak postrzegasz struktury kontroli w ogóle, meta struktur kontroli.
źródło
for
,if
,else
, iwhile
jako funkcji sprawia mi wywnioskować, że parametry do tych funkcji należy leniwie wykonywane w celu zachowują się tak samo jak oryginalne konstrukcje. Byłoby miło wykonać leniwą egzekucję.return
, wyjątków itp. Ale teraz ekspert programista ma w swoim zestawie narzędzi potężne dodatkowe narzędzie, jeśli zajdzie taka potrzeba. Poza tym języki IMHO nie powinny być „głupie”. Języki powinny mieć możliwość wspierania zwiększonej wiedzy specjalistycznej i wzrostu wiedzy z zakresu CS.Powiązany artykuł na pewno dobrze mówi o pętlach N + 1/2 Donalda Knutha . Wyrażony w C / C ++ / Java:
Jest to przydatne do odczytywania wierszy lub znaków z pliku, sprawdzania, czy osiągnięto EOF, a następnie przetwarzania go. Jestem tak przyzwyczajony do tego,
for(;;)..if(..)break;
że pojawia się wzór, że jest to dla mnie idiomatyczne. (Zanim przeczytałem artykuł Knutha, przedrukowany w książce Literate Programming , ten kiedyś był „wtf?”.)Knuth zasugerował słowa kluczowe
loop/while/repeat
:Gdzie
S
iT
są symbolami zastępczymi dla serii zer lub więcej instrukcji iC
jest to warunek logiczny. Gdyby nie byłoS
instrukcji, byłaby to pętla while, a gdyby nie byłoT
instrukcji, byłaby to pętla do.Konstrukcję tę można uogólnić, dopuszczając zero lub więcej
while C
klauzul, co czyni ją idealną do wyrażania nieskończonych pętli, a następnie niektórych rzadszych warunków, które wymagałyby dwóch kontroli.W tym samym artykule Knuth zasugerował mechanizm sygnalizacyjny, który byłby lokalną wersją wyjątków rzucania / wyłapywania (jako alternatywa dla używania goto).
Dla mnie? Chciałbym, aby Java wspierała optymalizację połączeń ogonowych, aby w razie potrzeby móc wyrazić dowolną ogólną strukturę sterowania.
Aktualizacja: zapomniałem wspomnieć, że wielu programistów C / C ++ / Java obchodzi ten problem, używając wbudowanego przypisania pod warunkiem
while
:Używając terminów z konstruktu Knutha, jest to dopuszczalne, gdy
S
iC
można je połączyć w jedno wyrażenie. Niektórzy ludzie nienawidzą zobaczyć wbudowanego zadanie wyżej, inni nienawidzą, aby zobaczyćbreak
wfor (;;)
góry. Ale kiedyS
iC
nie można go łączyć, na przykład gdyS
ma wiele instrukcji,for (;;)
jest to jedyna alternatywa bez powtarzania kodu. Inną alternatywą jest po prostu skopiowanieS
kodu:loop/while/repeat
Alternatywa Knutha wydaje się znacznie lepsza.źródło
repeat-until
pętli Pascala .do while ... loop until
- zarówno warunek wstępny, jak i końcowy są opcjonalne, a ja (niejasno) pamiętam używanie obu w jednej pętli. W twoim średnim stanie jest Adaexit when ...;
. Kluczową zaletąif ... break;
jest to, że możesz pisać,exit loopname when ...;
aby wyjść z wielu (ale niekoniecznie wszystkich) zagnieżdżonych pętli jednocześnie. Prawdopodobnie również nieco bardziej widoczny niż ta przerwa.Język BCPL miał
valueof
wyrażenie , którego można użyć do przekształcenia sekwencji instrukcji w jedno wyrażenie:Gdzie
some series of statements
może być wszystko, a całośćvalueof
oceniav
.Może to być przydatne w Javie, gdy trzeba obliczyć argument do wywołania a
this()
lubsuper()
(co wymaga, aby nic się przed nim nie wydarzyło). Oczywiście możesz po prostu napisać osobną metodę, ale może to być uciążliwe, jeśli musisz podać wiele lokalnych wartości dla kontekstu.Jeśli możesz użyć
final
zmiennych, które są potrzebne, możesz już zrobićvalueof
w Javie za pomocą anonimowych klas wewnętrznych:źródło
({ statement1; statement2; ...; result-expr; })
. Widziałem podobne gdzie indziej, ale nie pamiętam gdzie. Prawdopodobnie wszystkie skopiowane z BCPL.robi to samo co:
robi to samo co:
źródło
unless
.Z drugiej strony chciałbym zobaczyć lepszą obsługę iteratorów w językach programowania. W szczególności, gdy chcesz zejść dwie kolekcje w parach :
Niektóre dynamiczne języki mogą już to mieć lub łatwo obsługiwać za pomocą bibliotek i makr, ale myślę, że jest to zgodne z duchem twojego pytania.
Jeśli dwa zestawy nie są tego samego rozmiaru, może to spowodować wyjątek lub można użyć
else
pętli po, aby zasygnalizować różnicę rozmiarów.Oczywiście, możesz uogólnić to na zejście trzech lub więcej list.
Aktualizacja: Przydatne byłoby również wykonanie produktu kartezjańskiego między iteracjami:
co byłoby niczym więcej niż zagnieżdżonymi pętlami:
Jestem trochę zaniepokojony tym, że między dwoma zapisanymi tutaj notacjami istnieje różnica O (n) i O (n ^ 2) w liczbie par, z jedynie zmianą pojedynczego znaku.
źródło
for a, b, c in itertools.product(iter1, iter2, iter3):
daje leniwie oceniany produkt kartezjański. Co to jest? Chcesz także permutacji i kombinacji danego iteratora?itertools.permutations
,itertools.combinations
.Istnieje tak zwana „pętla Dijkstry” (zwana również „strzeżoną pętlą Dijkstry”). Został zdefiniowany w The Guarded Command Language (GCL) . Informacje na temat jego składni i semantycznej można znaleźć w powyższym artykule w Wikipedii w sekcji 6 Powtórzenie: do .
Obecnie znam jeden język programowania, który bezpośrednio obsługuje tę strukturę sterowania. Jest to Oberon-07 (PDF, 70 KB). I obsługuje „Pętlę Dijkstry” w formie instrukcji while. Spójrz na rozdział 9.6. Chociaż oświadczenia w powyższym pliku PDF.
PS To jest kopia mojej SO odpowiedzi .
źródło
Wyrażenia w stylu ikon z wbudowanym śledzeniem.
Python ma wiele zalet generatora ikon - i ogólnie robi z nich lepszą robotę, IMO. I w zasadzie cofanie było tylko rodzajem wyjątku, ale prostota wyrażeń była z grubsza odpowiednikiem ...
do obsługi przypadków awarii, takich jak dzielenie przez zero.
Gdzie Icon oszalał - brak operatorów porównujących zwracających wartość logiczną. Porównania zawsze albo się udawały, albo powodowały powrót do przeszłości, i istniała jeszcze inna kwestia semantyczna, którą desperacko próbuję sobie przypomnieć ... no powiedzmy, że jest to prawdopodobnie bardziej stłumione niż zapomniane.
Zawsze myślałem, że powinny mieć
if
wyrażenie bez żadnej innej części -if (condition, success-value)
coś w rodzaju cofania się, jeśli warunek zwraca wartość false - i porzucić dziwne porównania.EDYCJA Pamiętam - naprawdę oczywiste. Porównanie z dwoma argumentami kończy się powodzeniem lub niepowodzeniem - nie oblicza nowej wartości do zwrócenia. Więc kiedy to się uda, co powoduje powrót? Odpowiedź - jeden z argumentów. Ale jeśli napiszesz
a > b
, jaki logiczny argument należy zwrócić -a
lubb
? A jeślib < a
zamiast tego napiszesz ? Myślę , że zawsze zwracał właściwy argument, co ma tak samo sens, jak cokolwiek innego, ale nadal zwykle wydawał mi się niewłaściwy argument.źródło
To tylko ogólny pomysł i składnia:
TAKŻE warunek jest zawsze oceniany. ELSE działa jak zwykle.
Działa to również w przypadku. Prawdopodobnie jest to dobry sposób na wyeliminowanie instrukcji break:
można odczytać jako:
Nie wiem, czy jest to przydatne, czy łatwe do odczytania, ale to przykład.
źródło
Przychodzi mi na myśl kontynuacja Passing Style . W takim razie, oczywiście, chciałbyś również mieć Optymalizację ogona .
źródło
goto return ...;
instrukcji, która wyraźnie określa zamiar wywołania ogona, więc jeśli kompilator nie może wykonać iteracji, jest to błąd.Bezproblemowe rozgałęzianie wątków, ma składnię podobną do funkcji, ale wykonuje się w osobnym wątku i nie może uzyskać dostępu do danych, które początkowo nie zostały do niego przekazane.
Po wywołaniu gałęzi natychmiast zwróci uchwyt.
Za pomocą uchwytu można sprawdzić, czy zadanie zostało wykonane.
Jeśli wynik zostanie zażądany przed zakończeniem wykonywania, główny wątek po prostu zaczeka.
Nie obejmowałoby to bardziej zaawansowanych scenariuszy wielowątkowych, ale raczej zapewniałoby łatwo dostępny sposób rozpoczęcia korzystania z wielu rdzeni.
źródło
handle.finished()
test, alespawn
isync
wszystko, czego potrzebujesz do 90% zadań programowania równoległego.Bloki FIRST i THEN działają, jeśli którykolwiek z 3 warunków warunkowych zostanie oceniony jako prawdziwy. PIERWSZY blok działa przed blokiem warunkowym, a THEN po uruchomieniu bloku warunkowego.
Zapis warunkowy lub końcowy ELSE po instrukcji FIRST i THEN są niezależne od tych bloków.
Może czytać jako:
Te funkcje to tylko formularz do czytania. Nie stworzyliby zasięgu. To bardziej jak gosub / powrót z Basic.
Przydatność i czytelność jako przedmiot dyskusji.
źródło
Czasami piszę pętlę, która musi zrobić coś innego podczas pierwszej iteracji. Na przykład wyświetlanie tagów <th> zamiast tagów <td>.
Sytuację tę rozwiązuję za pomocą flagi logicznej. Coś takiego:
Głupio wydaje się sprawdzanie wartości
first
każdej iteracji, gdy przez większość czasu będzie ona fałszywa.Chciałbym mieć opcję zapętlania, aby określić inną treść pętli podczas pierwszej iteracji. Nie byłoby potrzeby oddzielnej zmiennej. Skompilowany kod też nie potrzebuje jednego, ponieważ wygenerowany kod miałby dwa ciała, jeden dla pierwszej iteracji, a drugi dla reszty.
źródło
print(out, first "<th>" then "<td>")
if (!first) gimme-a-comma ();
, ale w zasadzie to samo. Miałbym jednak zastrzeżenie - jeśli odpowiednio go zawrzesz, skończysz z takimi metodami, jak metoda łączenia ciągów w języku Python - jakkolwiek często potrzebujesz podstawowego wzorca, nie trzeba tak często przepisywać podstawowej pętli.if (!first)
, ale mikrooptymalizatorzy mogą budzić zastrzeżenia dotyczące przewidywania gałęzi.if (!first)
i pozwolić kompilatorowi optymalizującemu zdecydować, czy korpus pętli jest wystarczająco mały, aby rozwinięcie i pozbyciefirst
się było wygraną netto.[skopiowane z mojej własnej odpowiedzi na stackoverflow]
ignoring
- Aby zignorować wyjątki występujące w określonym bloku kodu.Ignorując konstrukcję kontrolną, możesz napisać ją w bardziej zwięzły i czytelny sposób:
[Scala udostępnia tę (i wiele innych konstrukcji kontroli wyjątków) w swojej standardowej bibliotece, w pakiecie util.control. ]
źródło
try..catch
blok to jedno; zmusza cię do rozpoznania błędu i celowego zignorowania go; podczas gdy wyrzucanie fragmentów kodu pod globalne ignorowanie może prowadzić do problemów, gdy te wyjątki są zgłaszane, a także prowadzić do złych nawyków programistycznych.try
blok, tyle że zawiera listę wyjątków, które wychwytuje i ignoruje z przodu, a nie później. Może to nawet stanowić zaletę w zakresie czytelności - np. Powiadomienie czytelnika, że brakujący plik nie jest błędem, nawet przed odczytaniem otwartego wywołania.Zamiast:
Zrób to w Pythonie, a teraz także w języku C #:
Scala ma wiele nowych funkcji.
Wreszcie, języki takie jak Clojure można rozszerzyć, aby zapewnić dodatkową funkcjonalność.
źródło
Mam dwa pomysły.
Często stwierdzam, że powtarzam się w
catch
blokach. Można to nieco pomóc poprzez wyodrębnienie metod, ale może to powodować niepotrzebne zaśmiecenie, jeśli metody są bardzo krótkie lub w inny sposób nie są warte metody. Byłoby więc dobrze zagnieżdżaćcatch
bloki:W programowaniu internetowym często też robię coś takiego (to nie jest prawdziwy przykład, więc nie analizuj fikcyjnych przypadków):
W Javascript (cóż, ECMAScript i może inne, których nie znam), ponieważ każda wartość może być oceniona jako warunek,
||
może pomóc.Naprawdę podoba mi się, jak to wygląda i chciałbym, żeby więcej języków, szczególnie po stronie serwera, miało wsparcie. (PHP może ocenić wszystko jako warunek, ale konwertuje całe wyrażenie warunkowe na wartość logiczną zamiast zachowywać wartość. Nie wiem o Pythonie lub Ruby.) Może stać się niewygodny po około trzech przypadkach, ale jeśli masz więcej niż trzy przypadki, możesz mieć również zły projekt oprogramowania.
źródło
x if c else y
składni, głównym powodem, że się było, ponieważ wiele wyrażeń za pomocą tych semantykę||
i&&
były subtelnie buggy. IIRC częstym przypadkiem była wartość (taka jak zero), która była ważna dla aplikacji traktowanej jakofalse
, a zatem została odrzucona, aby zamiast tego użyto nieprawidłowej rezerwy. Jednak - patrz moja odpowiedź WRT Język programowania ikon, który może mieć takie wyrażenia jakget1() else get2() else default
.Uogólniony przełącznik powiedział powyżej:
W Haskell:
źródło
W C # chciałbym używać prostych
switch () { ... }
, ale rozszerzalnych z takimi wyrażeniami:I tak dalej. To samo z numerami lub innych rodzajów (który obsługuje
IComparable
,IConvertible
...)To może uczynić mój kod bardziej lakonicznym i czytelnym.
źródło
To zabawne pytanie, jak powiedział @Macneil.
Moją ulubioną niezwykłą strukturą kontrolną, którą odkryłem (skromny kaszel), jest wykonywanie różnicowe .
Ma pewne zastosowania. Dla mnie przytłaczające zastosowanie to programowanie interfejsów użytkownika, co jest przykładem bardziej ogólnego problemu utrzymywania nadmiarowych danych w korespondencji. Z jednej strony są dane aplikacji, az drugiej strony są kontrolki interfejsu użytkownika, które muszą być uzgodnione. To brzmi jak „wiązanie”, ale tak naprawdę jest o wiele więcej.
Zwykle implementuję go za pomocą makr w C lub C ++. W C # muszę to zrobić ręcznie rozwijając instrukcje. To jest ból, ale działa.
Kiedyś zaimplementowałem to pod kątem makr Lisp, a potem było bardzo czyste. Nie wymagało to od programisty ostrożności. Mógłbym zrobić to samo w innym języku ustrukturyzowanym, gdybym zadał sobie trud napisania kompletnego parsera, a następnie wygenerowania wszystkich właściwych rzeczy. To duży projekt i jeszcze tego nie zrobiłem.
źródło
„Tradycyjne” struktury kontrolne, takie jak
for
kontrolowanie pracującego człowieka, utrzymują go podporządkowanym skorumpowanym ideologiom rządzącej elity kapitalistycznej. Dlatego używam alternatywnych struktur kontrolnych takich jakph0r
zamiast. To jakfor
, ale bardziej radykalne: nie złapieszph0r
noszenia garnituru i krawata, wyrzucając korporacyjne BS.ph0r
utrzymuje to, stary.Walcz z mocą!
źródło
Najprostsza
for
pętlaźródło