Haskell: Могу ли я использовать предложение where после блока с операторами связывания (>> =)? - PullRequest
10 голосов
/ 21 июля 2009

У меня очень простой вопрос. Я хотел бы использовать предложение where после блока кода, который использует операторы связывания, но я получаю ошибку компиляции.

Вот простой пример:

main =
    putStrLn "where clause test:" >>
    return [1..10] >>= \list ->
    print list'
        where list' = reverse list -- test1.hs:5:28: Not in scope: `list'

Я могу использовать предложение let для списка, как в

main =
    putStrLn "where clause test:" >>
    return [1..10] >>= \list ->
    let list' = reverse list -- works of course
    in print list'

но мне бы очень понравилось, если бы я мог использовать предложение where ...

Я также пытался сделать нотацию

main = do
    putStrLn "where clause test:"
    list <- return [1..10]
    print list'
        where list' = reverse list --test3.hs:5:30: Not in scope: `list'

Та же проблема. Могу ли я использовать условие where в этих обстоятельствах?

Ответы [ 3 ]

11 голосов
/ 21 июля 2009

Проблема в том, что let - in является выражением, которое может использоваться внутри других выражений, тогда как where может использоваться только в объявлении (module | class | instance | GADT | ...) или (функция | шаблон) привязка.

Из отчета на Haskell 98 о объявлениях и привязках ,

p | г 1 = e 1
| г 2 = e 2
& Hellip;
| г м = е м
where { decls }

это сахар для

p = let decls in
if г 1 then e 1 else
if г 2 then e 2 else
& Hellip;
if г м then е м else error "Unmatched pattern"

или, упрощая вещи, убрав охрану,

p = e where { decls }

является сахаром для

p = let decls in e

в привязках функций и шаблонов. Это верно даже тогда, когда ваша e является do { & hellip; } конструкцией.

Если вы хотите иметь локальную привязку к определенному подвыражению в большем выражении, вам нужно использовать let - in (или просто let внутри do, но это просто сахар для let -. in)

Вы даже не можете написать

main = do
    putStrLn "where clause test: "
    list <- return [1..10]
    (print list' where list' = reverse list)

, поскольку " e where { decls }" не является юридическим выражением & ndash; where может использоваться только в объявлениях и привязках.

main = do
    putStrLn "where clause test: "
    list <- return [1..10]
    let list' = list'' where list'' = reverse list
    print list'

Это законно (если несколько надумано).

11 голосов
/ 21 июля 2009

Как объясняет ephemient, вы не можете использовать where предложения так, как вы это делаете.

Ошибка происходит, потому что в этом коде:

main =
  return [1..10] >>= \list ->
  print list'
    where
      list' = reverse list

Предложение where присоединено к основной функции.

Вот та же функция с большим количеством скобок:

main = return [1..10] >>= (\list -> print list')
  where
    list' = reverse list

Я думаю, совершенно очевидно, почему вы получаете ошибку "out of scope": привязка для list находится глубоко внутри выражения main, а это не то, чего может достичь предложение where.

Что я обычно делаю в этой ситуации (и меня укусило одно и то же несколько раз). Я просто представляю функцию и передаю list в качестве аргумента.

main = do
  list <- return [1..10]
  let list' = f list
  print list'
  where
    f list = reverse list -- Consider renaming list,
                          -- or writing in point-free style

Конечно, я представляю, что ваш реальный код в функции f намного больше, чем просто reverse, и поэтому вы хотите, чтобы он был внутри предложения where вместо встроенной привязки let. Если код внутри функции f очень маленький, я просто напишу его внутри привязки let и не буду тратить время на ввод новой функции.

1 голос
/ 21 июля 2009

Насколько я могу судить, предложение where используется только в локальных привязках . Внутренняя часть оператора привязки >> (=) не является локальной привязкой (два разных вида привязок в этом предложении).

Сравните с этим:

main = f [1..10]

f list =
    putStrLn "where clause test:" >> print list'
        where list' = reverse list

Возможно, вы захотите обратиться к отчету о синтаксисе на Haskell 98 - не знаете, сколько это поможет.

Если я ошибаюсь, кто-то наверняка исправит меня, но я уверен, что вы вообще не можете использовать выражение where в стиле, который вы показали выше. list никогда не будет находиться в области действия условия where, если это не параметр функции.

...