2015-06-07 6 views
5

Używam GHC w wersji 7.8.3 na Windows 7.Jak poprawnie używać wyrażeń monadycznych w Haskell bez generowania błędów analizy?

Ok, nie chodzi o wyszukane fragmenty kodu. Po prostu staram się nie być noobem i faktycznie skompilować coś w sposób, który niejasno przypomina strukturę języków efektów ubocznych.

Mam następujący kod:

main = 
    do { 
    let x = [0..10]; 
    print x 
} 

I've learned here, że słowo kluczowe zrobić to fantazyjny cukier syntaktyczny dla fantazyjnych wyrażeń monadycznych. Gdy próbuję go skompilować, pojawia się następujący błąd:

main.hs:4:1: parse error on input 'print' 

A ja nauczyłem się w this other question, że zakładki w Haskell są złe, więc starałem się je pominąć:

main = 
    do { 
let x = [0..10]; 
print x 
} 

I nie udało mi się niestety, ponieważ błąd parsowania nadal występuje.

I've also learned here, że druk jest cukier syntaktyczny dla fancy odpowiednik:

main = 
    do { 
    let x = [0..10]; 
    putStrLn $ show x 
} 

Ale wtedy ten błąd zamiast:

main.hs:4:9: parse error on input 'putStrLn' 

Próbując zmierzyć moją rozpacz, Próbowałam pominąć słowo kluczowe "let", after reading this answer:

main = 
    do { 
    x = [0..10]; 
    print x 
} 

A potem otrzymam:

main.hs:4:1: parse error on input '=' 

I w ostatecznej, bezużytecznej próbie, próbowałem nawet pominąć ";" tak:

main = 
    do { 
    let x = [0..10] 
    print x 
} 

I got:

main.hs:4:1: parse error on input 'print' 

Więc

Jak prawidłowo używać monadycznego wyrażenia w Haskell bez uzyskania błędy analizowania? Czy jest jakaś nadzieja?

+3

Jeśli używasz wyraźne szelki wydaje parser wymaga 'in' w rachunku pozwolisz. Więc 'do {let x = 10; print x} 'nie działa, ale' do {let x = 10 in print x} 'robi. Ewentualnie pomiń nawiasy klamrowe i możesz pominąć wyraz "w". – user2407038

Odpowiedz

4
main = do let x = [0..10] 
      print x 

działa na mnie

i tak nie

main = do { let x = [0..10] 
      in print x } 

Chyba próbujesz mieszać kilka różnych opcji składni górę.

5

miałem do powiedzenia, bez użytecznych informacji, które

main = do 
    let x = [0..10] 
    print x 

pracował dla mnie, ale jestem teraz poza przeczytać o in w nawiasach.

Jako lekki dodatek znalazłem http://echo.rsmw.net/n00bfaq.html bardzo przydatny do czytania o identyfikacji/formatowaniu.

15

Zajęło mi trochę czasu, aby zobaczyć, co się rzeczywiście dzieje tutaj:

main = 
    do { 
    let x = [0..10]; 
    print x 
} 

Powyższe wygląda tak, jeśli mamy do z dwóch sprawozdań, które jest w porządku. Oczywiście nie jest powszechną praktyką stosowanie jawnych nawiasów klamrowych i półokrągłych, gdy wcięcie implicite je wstawia. Ale nie powinny boleć ... dlaczego to się nie powiedzie?

Prawdziwym problemem jest to, że let otwiera nowy blok! Blok let nie ma nawiasów klamrowych, więc obowiązuje reguła wcięcia. Blok zaczyna się od definicji x = [0..10]. Następnie znajduje się średnik, który obiecuje, że następna definicja pojawi się np.

let x = [0..10] ; y = ... 

lub nawet

let x = [0..10] ; 
     y = ...  -- must be indented as the x above, or more indented 

Jednak po średnikiem znaleźć print, który jest nawet mniej niż x wgniatany. Zgodnie z zasadą wcięcia, jest to równoznaczne z włożeniem szelki jak:

main = 
    do { 
    let { x = [0..10]; } 
    print x 
} 

ale powyżej nie analizuje. Komunikat o błędzie nie odnosi się do implicite wstawionych nawiasów klamrowych (które byłyby bardzo mylące!), Ale tylko do następnej linii (prawie tak samo mylącej w tym przypadku, niestety).

Kod można naprawić za pomocą np. zapewniając wyraźne szelki dla let:

main = do { let { x = [0..10] }; 
      print x } 

Powyżej wcięcie jest całkowicie bez znaczenia: można dodać przerwy i/lub przestrzenie liniowe bez wpływu na parsowanie (na przykład jak w Javie, C, etc.). Alternatywnie, można przesunąć średnika poniżej

main = do { let x = [0..10] 
      ; print x } 

Powyższy średnika w następnym wierszu i mniej urozmaiconej niż x, pośrednio wstawienie } która zamyka blok let. Tutaj wcięcie ma znaczenie, ponieważ let używa reguły wcięcia. Jeśli naciśniemy średnik więcej, możemy spowodować ten sam błąd analizy, który znaleźliśmy wcześniej.

Oczywiście, najbardziej idiomatyczne wybór stosuje regułę wcięcia dla całego kodu:

main = do let x = [0..10] 
      print x 
+2

Świetna odpowiedź, jestem nowy w Haskell (dlatego przeglądam pytania SO), co pomogło wypełnić puste pola. – Chris

+0

Bardzo, bardzo dobrze! Tak, to było bardzo pomocne i teraz rozumiem je całkowicie (I pomoże to innym zagubionym duszom w przyszłości) –

+0

Gdybym nie spędził tylko miesiąca czytając Raport, ja też nie miałbym pojęcia, co mówisz o ... Dobrze grałeś! – MathematicalOrchid

Powiązane problemy