Хаскелл: где против лет - PullRequest
104 голосов
/ 06 декабря 2010

Я новичок в Хаскеле, и меня очень смущает Где против Пусть .Они оба, кажется, обеспечивают схожую цель.Я прочитал несколько сравнений между Где против Пусть , но у меня возникают проблемы с выбором, когда использовать каждый из них.Может ли кто-нибудь предоставить какой-то контекст или, возможно, несколько примеров, демонстрирующих, когда использовать один над другим?

Где против Позвольте

Предложение where может быть определено только вуровень определения функции.Обычно это совпадает с областью определения let. Разница лишь в том, что используются охранники .Сфера применения where распространяется на всех охранников.Напротив, область действия выражения let представляет собой только текущее функциональное предложение и охрану, если таковые имеются.

Шпаргалка Haskell

Haskell Wiki очень подробный и предоставляет различные случаи, но использует гипотетические примеры.Я считаю его объяснения слишком краткими для начинающего.

Преимущества Let :

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

Control.Monad.State

не будет работать, потому что где ссылается на шаблон, соответствующий f =, где x не находится в области видимости.Напротив, если бы вы начали с let, то у вас не было бы проблем.

Haskell Wiki о преимуществах Let

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

Преимущества Where :

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)

Декларация против выражения

В вики Haskell упоминается, что Где *Предложение 1061 * является декларативным, а выражение Let - выразительным.Помимо стиля, как они работают по-разному?

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. В первом примере почему Let в области видимости, но Где нет?
  2. Можно ли применить Где к первому примеру?
  3. Может ли кто-нибудь применить это к реальным примерам, где переменные представляют фактические выражения?
  4. Есть лиобщее правило следовать, когда использовать каждый?

Обновление

Для тех, кто позже перейдет по этой теме, я нашел лучшее объяснение, которое можно найти здесь: " Нежное введение в Haskell ".

Выражения let.

Выражения let Haskell полезны всякий раз, когда требуется вложенный набор привязок.В качестве простого примера рассмотрим:

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

Набор привязок, созданных выражением let, является взаимно рекурсивным, а привязки шаблонов обрабатываются как ленивые шаблоны (то есть, они несут неявные ~).Единственный вид разрешенных объявлений - это сигнатуры типов, привязки функций и привязки шаблонов.

Where Clauses.

Иногда удобно связывать привязки по нескольким защищенным уравнениям, для чего требуется условие where:

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

Обратите внимание, что этого нельзя сделать с помощьюlet expression, которое охватывает только выражение, которое оно заключает.Предложение where допускается только на верхнем уровне набора уравнений или выражения case.Те же свойства и ограничения для привязок в выражениях let применяются к тем, в которых предложения where.Эти две формы вложенной области видимости кажутся очень похожими, но помните, что выражение let - это выражение, тогда как предложение where - нет - это часть синтаксиса объявлений функций и выражений case.

Ответы [ 4 ]

35 голосов
/ 06 декабря 2010

1: проблема в примере

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

- параметр x.Вещи в предложении where могут относиться только к параметрам функции f (их нет) и вещам во внешних областях.

2: чтобы использовать where в первом примере, выможет ввести вторую именованную функцию, которая принимает x в качестве параметра, например:

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

или примерно так:

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

3: Вот полный пример без... 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: Когда использовать let или where - дело вкуса.Я использую let, чтобы подчеркнуть вычисления (перемещая их вперед) и where, чтобы подчеркнуть ход программы (перемещая вычисления назад).

24 голосов
/ 06 декабря 2010

Несмотря на то, что есть техническая разница в отношении охранников, о которых говорил Эфимент, существует также концептуальная разница в том, хотите ли вы поставить основную формулу заранее с дополнительными переменными, определенными ниже (where), или же вы хотите определить все заранее и поставьте формулу ниже (let). Каждый стиль имеет свой акцент, и вы видите, что оба используются в математических работах, учебниках и т. Д. Как правило, переменные, которые достаточно неинтуитивны, чтобы без них формула не имела смысла, должны быть определены выше; Переменные, которые являются интуитивно понятными благодаря контексту или их именам, должны быть определены ниже. Например, в примере с ephemient hasVowel значение vowels очевидно, и поэтому его не нужно определять над его использованием (не принимая во внимание тот факт, что let не будет работать из-за охраны).

11 голосов
/ 06 декабря 2010

Юридический:

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

Юридический:

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

Юридический:

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

Юридический: (в отличие от ОД)

let vowels = "AEIOUaeiou"
in hasVowel = ...
3 голосов
/ 15 февраля 2015

Я нашел этот пример из LYHFGG полезным:

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

let - это выражение, поэтому вы можете поместить let в любое место (!) , куда могут идти выражения.

Другими словами, в приведенном выше примере не можно использовать where для простой замены let (без использования, возможно, более подробного case выражения в сочетании с where).

...