2017-10-01 47 views
28

W bazie kodu Czytam, znalazłem deklarację funkcji tak (brakuje niektórych części):Co robi przecinek w składni straży?

filepathNormalise :: BS.ByteString -> BS.ByteString 
filepathNormalise xs 
    | isWindows, Just (a,xs) <- BS.uncons xs, sep a, Just (b,_) <- BS.uncons xs, sep b 
    = '/' `BS.cons` f xs 

Co przecinek robić tutaj?

(tylko jako bonus, jeśli ktoś wie, to łatwo: jest to składnia wspomniano w Haskell Programowanie z pierwszych zasad, a jeśli tak, to gdzie jak nie pamiętam czytanie o nim?).

+3

Przypuszczam jest equivalen do logiczny i? Ale mogę sobie wyobrazić, inni początkujący haskell będą mieli to samo pytanie i dlatego pomyślałem, że to jest dobre, aby podnieść to jako pytanie na temat stackoverflow. – Krom

+0

, nawet jeśli znałeś odpowiedź, dobrze byłoby zamieścić to pytanie (być może wraz z odpowiedzią, jeśli tak było). –

+0

zaktualizowano [wiki] (https://wiki.haskell.org/Keywords#.2C). –

Odpowiedz

27

Osłony są opisane w Haskell 2010 section 3.13, Case Expressions (ta część jest o ekspresji przypadków, zgłoszeń nie najwyższym poziomie, ale przypuszczalnie semantyka są takie same)

guards → | guard1, …, guardn  (n ≥ 1) 
guardpat <- infixexp   (pattern guard) 
     | let decls    (local declaration) 
     | infixexp    (boolean guard)

Dla każdego strzeżonego wyrażenia, oddzielone przecinkami osłony są wypróbowywane sekwencyjnie od lewej do prawej. Jeśli wszystkie z nich się uda, to odpowiadające wyrażenie jest oceniane w środowisku rozszerzonym o powiązania wprowadzone przez strażników. Oznacza to, że wiązania wprowadzone przez strażnika (przez użycie klauzuli let lub wzorca) znajdują się w zasięgu następujących strażników i odpowiedniego wyrażenia. Jeśli któryś ze strażników się nie powiedzie, to wyrażenie strzeżone zawodzi, a następne strzeżone wyrażenie zostaje wypróbowane.

W prostym przypadku przecinek pełni rolę podobną do Boolean i. Ale przecinek jest mocniejszy, ponieważ każdy strażnik może wprowadzić nowe wiązania, które są używane przez kolejnych strażników (postępując od lewej do prawej).

Przecinki w strażnikach są dość rzadkie (przynajmniej z mojego doświadczenia), że opisałbym tę funkcję jako ciekawostki Haskella - w ogóle nie jest konieczne pisanie (lub, w większości, czytanie) Haskella. Podejrzewam, że z tego powodu program Haskell z pierwszej zasady pomija go.

+3

Cytowałeś definicję, ale wydaje się, że przegapiłeś ważną część: "** wiązania, które wprowadza strażnik ... są w zasięgu następujących strażników **". Jest to oczywiście niemożliwe, jeśli zastąpisz wszystkie przecinki słowami '&&' s. Na przykład porównaj 'case() z {() | x <- 1, x == 1 -> True} 'with' case() z {() | x <- 1 && x == 1 -> True} '. Kod pytany w pierwotnym pytaniu zawiera nawet użycie tej funkcji. – amalloy

+1

@amalloy Rzeczywiście. Ta funkcja nie jest nadmiarowa, gdy w grę wchodzą szablony 'p <- e' lub' let x = e'. Jeśli strażnik używa tylko wyrażeń logicznych, to przecinki mogą być zastąpione przez '&&'. Powiedziałbym, że idiomatyczny Haskell używa '&&' jeśli to możliwe. – chi

+0

Ach, dziękuję, tak, byłem zupełnie nieostrożny. Dokona odpowiednich poprawek. –

2

Ta składnia nie jest legalna w Haskell '98; Zostało to dodane do specyfikacji językowej w Haskell 2010. Jest to część rozszerzenia językowego "wzorca".

https://prime.haskell.org/wiki/PatternGuards

prawdziwy przydatność w to w co pozwala na wzór meczu wewnątrz klauzuli straży. Zmiana syntaktyczna ma również efekt uboczny, pozwalając użytkownikowi na łączenie kilku terminów Boole'a za pomocą przecinków.

(ja osobiście bardzo lubię to rozszerzenie, a ja jestem trochę w szoku, że znalazły się w oficjalnej specyfikacji, ale nie jesteśmy ...)