Haskell: Where vs. Let

Jestem nowy w Haskell i jestem bardzo zdezorientowany gdzie vs. Let. Oba wydają się mieć podobny cel. Przeczytałem kilka porównań pomiędzy gdzie vs. Let ale mam problem z rozeznaniem, kiedy użyć każdego. Czy ktoś mógłby podać jakiś kontekst lub może kilka przykładów, które pokazują, kiedy używać jednego nad drugim?

Gdzie kontra Let

Klauzula where może być zdefiniowana tylko na poziomie definicja funkcji. Zazwyczaj jest to tożsame z zakresem definicji let. jedyną różnicą jest to, kiedy strażnicy są używane . Zakres klauzuli where rozciąga się na wszystkie straże. W przeciwieństwie do tego, Zakres wyrażenia let jest tylko bieżącą klauzulą funkcji i strażnikiem, jeśli istnieje.

Haskell Ściągawka

Haskell Wiki jest bardzo szczegółowa i zawiera różne przypadki, ale wykorzystuje hipotetyczne przykłady. Znajduję jego wyjaśnienia zbyt krótkie jak na początkującego.

Zalety Let :

f :: State s a
f = State $ \x -> y
   where y = ... x ...

Kontrola.Monad.Stan

Nie zadziała, bo gdzie odnosi się do wzór pasujący f =, gdzie nie ma x jest w zasięgu. Natomiast, jeśli zaczęło się od let, wtedy nie mieć kłopoty.

Haskell Wiki o zaletach Let

f :: State s a
f = State $ \x ->
   let y = ... x ...
   in  y

Zalety miejsca :

f x
  | cond1 x   = a
  | cond2 x   = g a
  | otherwise = f (h x a)
  where
    a = w x

f x
  = let a = w x
    in case () of
        _ | cond1 x   = a
          | cond2 x   = g a
          | otherwise = f (h x a)

Deklaracja vs. Wyrażenie

Haskell wiki wspomina, że gdzie klauzula jest deklaratywna, podczas gdy niech wyrażenie jest ekspresyjne. Pomijając styl, w jaki sposób działają inaczej?

Declaration style                     | Expression-style
--------------------------------------+---------------------------------------------
where clause                          | let expression
arguments LHS:     f x = x*x          | Lambda abstraction: f = \x -> x*x
Pattern matching:  f [] = 0           | case expression:    f xs = case xs of [] -> 0
Guards:            f [x] | x>0 = 'a'  | if expression:      f [x] = if x>0 then 'a' else ...
  1. w pierwszym przykładzie dlaczego Let jest w zakresie, ale gdzie nie jest?
  2. czy można zastosować gdzie do pierwszego przykładu?
  3. czy niektórzy mogą zastosować to do rzeczywistych przykładów, w których zmienne reprezentują rzeczywiste wyrażenia?
  4. czy istnieje ogólna zasada, której należy przestrzegać, kiedy używać każdego z nich?

Update

Dla tych, którzy przychodzą do tego wątku później znalazłem najlepsze wyjaśnienie, aby znaleźć tutaj: " łagodne wprowadzenie do Haskell {30]}".

Niech Wyrażenia.

Wyrażenia niech Haskella są użyteczne ilekroć zagnieżdżony zestaw wiązań jest wymagane. Jako prosty przykład, consider:

let y   = a*b
    f x = (x+y)/y
in f c + f d

Zestaw wiązań created by a let wyrażenie jest wzajemnie rekurencyjne, a wiązania wzorcowe traktowane są jako leniwe wzorce (tzn. niosą ze sobą implicit ~). Jedyny rodzaj deklaracji dozwolone są podpisy typów, wiązania funkcyjne i wzór wiązania.

Gdzie

Czasami jest to wygodne, aby zakres wiązania na kilku strzeżonych równań, co wymaga gdzie klauzula:

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 tylko zakresy nad wyrażeniem, które zamyka. Klauzula where jest dozwolona tylko na najwyższym poziomie zbioru równań lub wyrażeń przypadków. Te same właściwości i ograniczenia dotyczące powiązań w wyrażeniach niech mają zastosowanie do tych w klauzulach where. Te dwie formy zagnieżdżonego zakresu wydają się bardzo podobne, ale pamiętaj, że wyrażenie let jest wyrażeniem, podczas gdy klauzula where nie jest -- jest częścią składni deklaracji funkcji i wyrażeń case.

Author: nbro, 2010-12-06

4 answers

1: problem w przykładzie

f :: State s a
f = State $ \x -> y
    where y = ... x ...

Jest parametrem x. Rzeczy w klauzuli where mogą odnosić się tylko do parametrów funkcji f (nie ma ich) oraz rzeczy w zewnętrznych zakresach.

2: aby użyć where w pierwszym przykładzie, możesz wprowadzić drugą nazwaną funkcję to przyjmuje x jako parametr, jak to:

f = State f'
f' x = y
    where y = ... x ...

Lub tak:

f = State f'
    where
    f' x = y
        where y = ... x ...

3: Oto kompletny przykład bez ... ' s:

module StateExample where

data State a s = State (s -> (a, s))

f1 :: State Int (Int, Int)
f1 = State $ \state@(a, b) ->
    let
        hypot = a^2 + b^2
        result = (hypot, state)
    in result

f2 :: State Int (Int, Int)
f2 = State f
    where
    f state@(a, b) = result
        where
        hypot = a^2 + b^2
        result = (hypot, state)

4: kiedy stosować let lub where to kwestia gustu. Używam let, aby podkreślić obliczenia (przesuwając je do przodu) i where, aby podkreślić przepływ programu (przesuwając obliczenia do tyłu).

 32
Author: antonakos,
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
2010-12-06 03:00:11

Chociaż istnieje techniczna różnica w odniesieniu do strażników, że ephemient wskazał, istnieje również różnica pojęciowa w tym, czy chcesz umieścić główną formułę z góry z dodatkowymi zmiennymi zdefiniowanymi poniżej (where) lub czy chcesz zdefiniować wszystko z góry i umieścić formułę poniżej (let). Każdy styl ma inny nacisk i widzisz oba używane w papierach matematycznych, podręcznikach itp. Ogólnie zmienne, które są na tyle nieintuicyjne, że formuła nie ma sensu bez nich powinny być zdefiniowane powyżej; zmienne intuicyjne ze względu na kontekst lub ich nazwy powinny być zdefiniowane poniżej. Na przykład, w przykładzie hasVowel ephemienta znaczenie vowels jest oczywiste, więc nie musi być zdefiniowane powyżej jego użycia (pomijając fakt, że let nie zadziała ze względu na strażnika).

 23
Author: gdj,
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
2010-12-06 01:36:28

Legal:

main = print (1 + (let i = 10 in 2 * i + 1))

Nie legalne:

main = print (1 + (2 * i + 1 where i = 10))

Legal:

hasVowel [] = False
hasVowel (x:xs)
  | x `elem` vowels = True
  | otherwise = False
  where vowels = "AEIOUaeiou"

Nie legalne: (w przeciwieństwie do ML)

let vowels = "AEIOUaeiou"
in hasVowel = ...
 11
Author: ephemient,
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
2010-12-06 01:20:44

Znalazłem ten przykład zLYHFGG pomocny:

ghci> 4 * (let a = 9 in a + 1) + 2  
42  

let jest wyrażeniem, dzięki czemu można umieścić let gdziekolwiek(!) gdzie wyrażenia mogą iść.

Innymi słowy, w powyższym przykładzie nie można użyć , aby zastąpić where (bez użycia bardziej wyrazistego case wyrażenia połączonego z where).

 2
Author: jhegedus,
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
2015-02-28 05:04:31