W Haskell, kiedy użyjemy in Z let?

W poniższym kodzie, ostatnią frazę mogę umieścić in z przodu. Czy to coś zmieni?

Kolejne pytanie: jeśli zdecyduję się umieścić in przed ostatnim zdaniem, czy muszę je wciąć?

Próbowałem bez wcięcia i przytula skarży się

Ostatni generator w do {...} must be an expression

import Data.Char
groupsOf _ [] = []
groupsOf n xs = 
    take n xs : groupsOf n ( tail xs )

problem_8 x = maximum . map product . groupsOf 5 $ x
main = do t <- readFile "p8.log" 
          let digits = map digitToInt $concat $ lines t
          print $ problem_8 digits

Edit

OK, więc ludzie nie rozumieją, co mówię. Powiem inaczej.: są następujące dwa takie same, biorąc pod uwagę kontekst powyżej?

1.

let digits = map digitToInt $concat $ lines t
print $ problem_8 digits

2.

let digits = map digitToInt $concat $ lines t
in print $ problem_8 digits

Kolejne pytanie dotyczące zakresu wiązań zadeklarowanych w let: przeczytałem tutaj , że:

where klauzule.

Czasami wygodnie jest zakreślić wiązania na kilku strzeżonych równaniach, co wymaga klauzuli where:

f x y  |  y>z           =  ...
       |  y==z          =  ...
       |  y<z           =  ...
     where z = x*x

Zauważ, że nie można tego zrobić za pomocą wyrażenia let, które obejmuje tylko wyrażenie , które zawiera.

Moje pytanie: tak więc zmienne cyfry nie powinny być widoczne dla ostatniej drukowanej frazy. Czy coś mnie ominęło?

Author: nbro, 2011-11-26

4 answers

Krótka odpowiedź : użyj let Bez in w ciele bloku do, a w części po | w zrozumieniu listy. Gdziekolwiek indziej, użyj let ... in ....


Słowo kluczowe let jest używane w Haskell na trzy sposoby.

  1. Pierwsza forma to let-expression.

    let variable = expression in expression
    

    Może być stosowany wszędzie tam, gdzie dozwolone jest wyrażenie, np.

    > (let x = 2 in x*2) + 3
    7
    
  2. Drugi jest let-statement. Ten formularz jest używany tylko wewnątrz do-notacji i nie używa in.

    do statements
       let variable = expression
       statements
    
  3. Trzeci jest podobny do numeru 2 i jest używany wewnątrz list compensions. Ponownie, nie in.

    > [(x, y) | x <- [1..3], let y = 2*x]
    [(1,2),(2,4),(3,6)]
    

    Forma ta wiąże zmienną, która znajduje się w zakresie w kolejnych generatorach oraz w wyrażeniu przed |.


Powodem twojego zamieszania jest to, że wyrażenia (właściwego typu) mogą być używane jako instrukcje w obrębie bloku do, a let .. in .. jest po prostu ekspresja.

Z powodu reguł wcięcia Haskella, linia wcięta dalej niż poprzednia oznacza, że jest kontynuacją poprzedniej linii, więc to {21]}
do let x = 42 in
     foo

Jest parsowany jako

do (let x = 42 in foo)

Bez wcięcia pojawia się błąd parsowania:

do (let x = 42 in)
   foo

Podsumowując, nigdy nie używaj in w zrozumieniu listy lub bloku do. Jest to niezauważalne i mylące, ponieważ konstrukcje te mają już swoją własną formę let.

 98
Author: hammar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-25 22:41:15

Po Pierwsze, po co się przytulać? Platforma Haskell jest ogólnie zalecanym sposobem dla początkujących, który jest dostarczany z GHC.

A teraz przejdźmy do słowa kluczowego let. Najprostszą formą tego słowa kluczowego jest zawsze {[41] } być używane z in.

let {assignments} in {expression}

Na przykład,

let two = 2; three = 3 in two * three

{assignments} tylko w zakresie odpowiadającym {expression}. stosuje się regularne zasady układu, co oznacza, że in musi być wcięte co najmniej tak samo jak let że odpowiada, a wszelkie pod-wyrażenia odnoszące się do wyrażenia let muszą również być wcięte co najmniej tak samo. Nie jest to w rzeczywistości 100% prawda, ale jest dobrą zasadą; reguły układu Haskell są czymś, do czego po prostu przyzwyczaisz się z czasem, gdy czytasz i piszesz kod Haskell. Należy pamiętać, że ilość wcięć jest głównym sposobem wskazywania, który kod odnosi się do jakiego wyrażenia.

Haskell oferuje dwa wygodne przypadki, w których nie musisz write in: składanie notacji i list (właściwie składanie monad). Zakres zadań dla tych wygodnych przypadków jest z góry określony.
do foo
   let {assignments}
   bar
   baz

Dla notacji do, {assignments} są w zakresie wszelkich twierdzeń, które następują, w tym przypadku, bar i baz, ale nie foo. To tak, jakbyśmy napisali

do foo
   let {assignments}
   in do bar
         baz

Składnia listy (a właściwie każde rozumienie monad) desugar w notację do, więc zapewniają podobną funkcję.

[ baz | foo, let {assignments}, bar ]

The {assignments} są w zakresie dla wyrażeń bar i baz, ale nie dla foo.


where jest nieco inny. Jeśli się nie mylę, zakres where odpowiada określonej definicji funkcji. Więc

someFunc x y | guard1 = blah1
             | guard2 = blah2
  where {assignments}

{assignments} w tym where klauzuli mają dostęp do x i y. guard1, guard2, blah1, oraz blah2 Wszystkie mają dostęp do {assignments} tej klauzuli where. Jak wspomniano w linkowanym samouczku, może to być pomocne, jeśli wielu strażników ponownie użyje tego samego wyrażenia.

 17
Author: Dan Burton,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-25 23:00:03

W notacji do można rzeczywiście używać let z i bez in. Aby to było równoważne (w Twoim przypadku, pokażę później przykład, gdzie trzeba dodać drugi do, a tym samym więcej wcięć), musisz wciąć go tak, jak odkryłeś (jeśli używasz layout - jeśli używasz jawnych nawiasów i średników, są one dokładnie równoważne).

Aby zrozumieć dlaczego jest to równoznaczne, trzeba faktycznie grok monad (przynajmniej w pewnym stopniu) i przyjrzeć się zasadom desugaringu dla do notacji. W szczególności, kod taki jak ten:

do let x = ...
   stmts -- the rest of the do block

Jest tłumaczone na let x = ... in do { stmts }. W Twoim przypadku, stmts = print (problem_8 digits). Ewaluacja całego desugared let wiązania skutkuje działaniem IO (z print $ ...). I tutaj, trzeba zrozumieć monady, aby intuicyjnie zgodzić się, że nie ma różnicy między notacjami do a "regularnymi" elementami języka opisującymi obliczenia skutkujące wartościami monadycznymi.

Jeśli chodzi o oba dlaczego są możliwe: Cóż, let ... in ... ma szeroki zakres zastosowań (większość które nie mają nic wspólnego z monadami w szczególności), i długą historię do rozruchu. let Bez in dla do notacja, z drugiej strony, wydaje się być niczym innym jak małym kawałkiem cukru składniowego. Zaleta jest oczywista: można powiązać wyniki czystych (jak w, nie monadycznych) obliczeń z nazwą bez uciekania się do bezsensownego val <- return $ ... i bez dzielenia do bloku na dwa:

do stuff
   let val = ...
    in do more
          stuff $ using val

Powodem, dla którego nie potrzebujesz dodatkowego bloku do do tego, co następuje let, jest to, że mam tylko jedną linię. Pamiętaj, do e jest e.

W odniesieniu do Twojej edycji: digit bycie widocznym w następnej linii jest całym punktem. I nie ma dla tego wyjątku. do notacja staje się jednym wyrażeniem i let działa dobrze w jednym wyrażeniu. where jest potrzebny tylko do rzeczy, które nie są wyrażeniami.

Dla zademonstrowania, pokażę Ci wersję Twojego bloku. Jeśli nie jesteś jeszcze zbyt zaznajomiony z monadami (coś, co powinno się wkrótce zmienić IMHO), zignorować operatora >>= i skupić się na let. Zauważ również, że wcięcie nie ma już znaczenia.
main = readFile "p8.log" >>= (\t ->
  let digits = map digitToInt $ concat $ lines t
  in print (problem_8 digits))
 6
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-25 22:41:19

Niektóre notatki dla początkujących o "podążają za dwoma tymi samymi".

Na przykład, {[3] } jest funkcją, która dodaje 1 do liczby:

add1 :: Int -> Int
add1 x =
    let inc = 1
    in x + inc

Więc, to jest jak {[4] } z podstawieniem inc przez 1 ze słowa kluczowego let.

Gdy próbujesz stłumić in słowo kluczowe

add1 :: Int -> Int
add1 x =
    let inc = 1
    x + inc

Masz błąd parse.

From documentation :

Within do-blocks or list comprehensions 
let { d1 ; ... ; dn } 
without `in` serves to introduce local bindings. 

Btw, są ładne Wyjaśnienie z wieloma przykładami na temat tego, co rzeczywiście robią where i in słowa kluczowe.

 1
Author: ДМИТРИЙ МАЛИКОВ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-25 22:37:05