Хаскелл: где против пусть
Я новичок в Haskell, и я очень смущен здесь и пусть. Они оба, кажется, обеспечивают аналогичную цель. Я прочитал несколько сравнений между здесь и пусть но у меня возникли проблемы лишь когда использовать каждый. Может ли кто-нибудь предоставить некоторый контекст или, возможно, несколько примеров, которые демонстрируют, когда использовать один над другим?
где и пусть
A
whereпредложение может быть определено только на уровне определения функции. Обычно это совпадает с областьюletопределение. единственная разница, когда охранники используются. Сфера примененияwhereпункт распространяется на всех охранников. В отличие от рамкиletвыражение-это только текущее предложение функции и guard, если таковые имеются.
The Haskell Wiki очень подробно и предоставляет различные случаи, но использует гипотетические примеры. Я нахожу его объяснения слишком краткими для новичка.
преимущества Let:
f :: State s a
f = State $ x -> y
where y = ... x ...
не будет работать, потому что куда относится
соответствие шаблону f =, где нет x
находится в поле зрения. Напротив, если бы вы имели
начал с let, а потом не стал бы
иметь тревогу.
Haskell Wiki on Преимущества 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 wiki упоминает, что здесь предложение является декларативным, в то время как пусть выражение выразительным. Помимо стиля, как они работают по-разному?
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 ...
- в первом примере, почему это пусть в рамках но здесь нет?
- можно ли применять здесь в первом примере?
- могут ли некоторые применить это к реальным примерам, где переменные представляют фактические выражения?
- есть ли общее эмпирическое правило, чтобы следовать, когда использовать каждый?
обновление
для тех, кто приходит по этой теме позже, я нашел лучшее объяснение, которое можно найти здесь:"введение в Хаскелл".
Давайте Выражений.
выражения Haskell let полезны
всякий раз, когда вложенный набор Привязок
требуемый. В качестве простого примера,
рассмотрим:
let y = a*b
f x = (x+y)/y
in f c + f d
набор Привязок, созданных let
выражение является взаимно рекурсивным, и
привязки шаблонов рассматриваются как ленивые
шаблоны (т. е. они несут неявный
~). Единственный вид деклараций
разрешены сигнатуры типов,
привязки функций, и узор
фурнитура.
Предложения Where.
иногда удобно к объему
привязки над несколькими охраняемыми
уравнения, для которых требуется где
статья:
f x y | y>z = ...
| y==z = ...
| y<z = ...
where z = x*x
обратите внимание, что это не может быть сделано с выражением let, которое охватывает только выражение, которое оно заключает. Предложение where допускается только на верхнем уровне набора уравнений или выражения case. Те же свойства и ограничения на привязки в выражениях let применяются к тем, в которых пункты. Эти две формы вложенной области кажутся очень похожими, но помните, что выражение let является выражением, тогда как предложение where не является -- это часть синтаксиса объявлений функций и выражений case.
4 ответов:
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чтобы подчеркнуть поток программы (перемещая вычисление назад).
хотя есть техническая разница в отношении охранников, на которые указал Эфемер, есть также концептуальная разница в том, хотите ли вы поместить основную формулу вперед с дополнительными переменными, определенными ниже (
where) или если вы хотите, чтобы определить все заранее и поставить формулу ниже (let). Каждый стиль имеет различный акцент, и вы видите, как используется в математических работах, учебниках и т. д. Как правило, переменные, которые достаточно неинтуитивны, что формула не делает смысл без них должен быть определен выше; переменные, которые интуитивно понятны из-за контекста или их имена должны быть определены ниже. Например, в Примере эфемерного hasVowel значениеvowelsочевидно, и поэтому его не нужно определять выше его использования (не обращая внимания на то, чтоletне будет работать из-за предохранителя).
Legal:
main = print (1 + (let i = 10 in 2 * i + 1))не законно:
main = print (1 + (2 * i + 1 where i = 10))Legal:
hasVowel [] = False hasVowel (x:xs) | x `elem` vowels = True | otherwise = False where vowels = "AEIOUaeiou"не законно: (в отличие от ML)
let vowels = "AEIOUaeiou" in hasVowel = ...
Я нашел этот пример от LYHFGG полезная:
ghci> 4 * (let a = 9 in a + 1) + 2 42
letэто выражение, так что вы можете поставитьletвезде(!) где выражения могут пойти.другими словами, в приведенном выше примере это не можно использовать
whereпросто заменитьlet(возможно, не используя некоторые более подробныеcaseвыражения в сочетании сwhere).
Comments