2009-07-21 6 views
9

У меня очень простой вопрос. Я хотел бы использовать предложение where после блока кода, который использует операторы связывания, но я получаю ошибку компиляции.Haskell: Могу ли я использовать предложение 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' 

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

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

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 в этих обстоятельствах?

ответ

10

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

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

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

where -clause прикрепляется к основной функции.

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

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 и не стал бы накладывать дополнительные функции на введение новой функции.

+0

Спасибо, ваш пример с большим количеством скобок очищает его для меня. –

1

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

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

main = f [1..10] 

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

Вы можете обратиться к Haskell 98 syntax report - не знаю, сколько помощь это будет.

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

+0

Лямбда-абстракция - это выражение, а не объявление или привязка, хотя оно может связывать новые имена ... – ephemient

+0

Whoa, кто это сделал? Я думаю, что это правильно, если не так полно, как могло бы быть. – ephemient

+0

это не имеет отношения к делу. OP хочет использовать «список», результат из середины кучи монадических вычислений; а не значение, которое из-за пределов монады – newacct

11

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

Из отчета о Haskell 98 на declarations and bindings,

p | g1=e1
    | g2=e2
    …
    | gm=em
  where {decls}

сахар для

p= letdeclsin
      ifg1thene1else
      ifg2thene2else
      …
      ifgmthenemelse error "Unmatched pattern"

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

p=ewhere {decls}

сахар для

как в функции, так и в виде привязок. Это верно даже тогда, когда ваш 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) 

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

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

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

+0

почему бы не просто «let list» = reverse list? в последнем примере? – newacct

+0

Спасибо, я должен ссылаться на отчет Haskell чаще, когда у меня есть фундаментальные вопросы о таком языке. –

+0

@newacct: Вопрос OP уже включает этот вариант, который, очевидно, работает. – ephemient