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

Fre*_*ois 10 syntax monads 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'
Run Code Online (Sandbox Code Playgroud)

我可以使用let子句作为列表'

main =
    putStrLn "where clause test:" >>
    return [1..10] >>= \list ->
    let list' = reverse list -- works of course
    in print list'
Run Code Online (Sandbox Code Playgroud)

但如果我能使用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'
Run Code Online (Sandbox Code Playgroud)

同样的问题.在这种情况下我可以使用where子句吗?

eph*_*ent 11

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

从Haskell 98关于声明和绑定的报告,

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

是糖

p = let decl 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

在功能和模式绑定中.即使你的edo {...... }构造,也是如此.

如果你想在一个更大的表达式中对一个特定的子表达式进行局部绑定,你需要使用let- in(或者只是let在一个内部do,但这只是糖的let- in).

你甚至不能写

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

因为" e where { decls } "不是合法表达式 - where只能用于声明和绑定.

main = do
    putStrLn "where clause test: "
    list <- return [1..10]
    let list' = list'' where list'' = reverse list
    print list'
Run Code Online (Sandbox Code Playgroud)

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


Tom*_*rst 11

正如ephemient所解释的那样,你不能where像你那样使用条款.

发生错误是因为在此代码中:

main =
  return [1..10] >>= \list ->
  print list'
    where
      list' = reverse list
Run Code Online (Sandbox Code Playgroud)

所述where-clause被附接到主函数.

这是具有更多括号的相同功能:

main = return [1..10] >>= (\list -> print list')
  where
    list' = reverse list
Run Code Online (Sandbox Code Playgroud)

我认为为什么你得到" 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
Run Code Online (Sandbox Code Playgroud)

当然,我想你在f函数中的实际代码更多,reverse这就是为什么你想要它在一个where子句中,而不是内联let绑定.如果f函数内部的代码非常小,我只是在let绑定中编写它,并且不会经历引入新函数的开销.