Haskell:我可以在带有绑定运算符的块之后使用where子句(>> =)吗?

时间:2009-07-21 02:02:37

标签: syntax haskell monads

我有一个非常简单的问题。我想在使用绑定运算符的代码块之后使用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 个答案:

答案 0 :(得分:11)

问题是let - in是一个表达式,可以在其他表达式中使用,而where只能用于(模块|类|实例| GADT)声明或(函数|模式)绑定。

来自Haskell 98报告declarations and bindings

  

p | g 1 = e 1
  | g 2 = e 2
  ...
  | g m = e m
  where { decls }

是糖的

  

p = let decls in
  if g 1 then e 1 else   if g 2 then e 2 else   ...
  if g m then e m else error "Unmatched pattern"

或者,通过删除警卫简化事情,

  

p = e where { decls }

是糖的

  

p = let decls in e

在函数和模式绑定中。即使您的 e do { ... }结构,也是如此。

如果您希望在较大的表达式中具有特定子表达式的局部绑定,则需要在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 }”不是合法表达式 - where只能用于声明和绑定。

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

这是合法的(如果有些人为)。

答案 1 :(得分:11)

正如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子句中,而不是内联{ {1}}绑定。如果let函数中的代码非常小,我只是将它写在f绑定中,并且不会经历引入新函数的开销。

答案 2 :(得分:1)

据我所知,where子句仅用于本地绑定。 &gt;(>)绑定语句的内部部分不是本地绑定(该句子中有两种不同的绑定)。

与此比较:

main = f [1..10]

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

您可能需要参考Haskell 98 syntax report - 不确定会有多少帮助。

如果我错了,有人肯定会纠正我,但我很确定你不能使用上面显示的样式中的where子句。 list永远不会在where子句的范围内,除非它是函数的参数。