2014-07-21 6 views
2

Следующий код не разобрать:Почему следующий код не анализируется?

main :: IO() 
main = do 
    print $ result 
     where result = foldl' (+) 0 [1..1000000] 
    print $ result 
     where result = last [1..1000000] 

Компилятор жалуется на второй печати: SRC/Main.hs: 10: 5: ошибка разбора на входе `печати»

Почему это?

ответ

9

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

main :: IO() 
main = do 
    print $ result 
     where result = foldl' (+) 0 [1..1000000] 

в точности эквивалентно:

main :: IO() 
main = do 
    print $ result 
    where result = foldl' (+) 0 [1..1000000] 

т.е. where определяет локальные определения для main не для print $ result линии. Поскольку where должен быть последней частью связывания, очевидно, следующее выражение print вызывает синтаксическую ошибку.

Чтобы использовать where внутри do -блок вы должны использовать его при определении let привязок, например, это (очень глупый пример):

main = do 
    let result = f 
     where f = foldl' (+) 0 [1..1000000] 
    print result 

Вы можете проверить это в grammar:

decl → gendecl 
     | (funlhs | pat) rhs 

rhs  → = exp [where decls] 
     | gdrhs [where decls] 

Обратите внимание, что where decls является частью rhs правила whic h определяет правую часть объявления. Если проверить правила exp вы не найдете where отметил:

exp  → infixexp :: [context =>] type  (expression type signature) 
     | infixexp 

infixexp → lexp qop infixexp    (infix operator application) 
      | - infixexp      (prefix negation) 
      | lexp 

lexp → \ apat1 … apatn -> exp    (lambda abstraction, n ≥ 1) 
     | let decls in exp     (let expression) 
     | if exp [;] then exp [;] else exp (conditional) 
     | case exp of { alts }    (case expression) 
     | do { stmts }      (do expression) 
     | fexp 
fexp → [fexp] aexp       (function application) 

aexp → qvar        (variable) 
     | gcon        (general constructor) 
     | literal 
     | (exp)        (parenthesized expression) 
     | (exp1 , … , expk)     (tuple, k ≥ 2) 
     | [ exp1 , … , expk ]     (list, k ≥ 1) 
     | [ exp1 [, exp2] .. [exp3] ]   (arithmetic sequence) 
     | [ exp | qual1 , … , qualn ]   (list comprehension, n ≥ 1) 
     | (infixexp qop)     (left section) 
     | (qop⟨-⟩ infixexp)     (right section) 
     | qcon { fbind1 , … , fbindn }  (labeled construction, n ≥ 0) 
     | aexp⟨qcon⟩ { fbind1 , … , fbindn } (labeled update, n ≥ 1) 
+0

Кроме того, обратите внимание, что 'пусть decls в exp' * это * упоминалось, и может быть использован вместо, когда вам это нужно. –

Смежные вопросы