Haskell where子句语法在do块中

Ral*_*lph 24 syntax haskell where-clause

我试图在Haskell中mapM_do块内重构一个函数调用.我想将lambda提取到(本地)命名函数,以使代码更具可读性.

我的代码最初看起来像这样:

do
  -- ...
  mapM_ (\x -> x + 1) aList

  return aValue
Run Code Online (Sandbox Code Playgroud)

我想改成它

do
  -- ...
  mapM_ func aList
    where func x = x + 1

  return aValue
Run Code Online (Sandbox Code Playgroud)

但我在线上遇到语法错误return aValue.我的实际lambda更复杂:-),但我确实用同样的lambda尝试它,以确保它不是lambda代码中的问题.

我该如何重写这段代码?我应该用let...... in代替吗?

C. *_*ann 33

这里有三种类似(但不同)的方法来定义东西:

  • 您可以where在某些定义之后附加子句 - 主要是方程式绑定.因此,你可以在函数的末尾添加一个函数,或者在使用let或使用around where子句定义之后.

  • 另一方面,let x = ... in ...是一个表达式,评估后面的部分in,这是后面的东西唯一let可见的地方.

  • 在一个do块内部,因为已经有一个隐式的范围嵌套(事物在首次定义后可见),你可以let x = ...单独使用.这与之前的形式完全相同 - 其余的do块之后let就是有效的in ...部分.

如果你想要一个使用do块内定义的东西的本地定义,你唯一的选择是第三个(或者将其他值作为参数传递).但是,对于像您的示例一样的独立辅助函数,任何样式都可以.以下是您的示例,以演示每个:

第一种样式,在func任何地方都可见foo,包括where子句中定义的任何其他内容:

foo = do ...
         mapM_ func aList
         ...
         return aValue
  where func x = x + 1
Run Code Online (Sandbox Code Playgroud)

第二种样式,func只在let表达式中可见,在这种情况下是整个do块:

foo = let func x = x + 1 
      in do 
         ...
         mapM_ func aList
         ...
         return aValue
Run Code Online (Sandbox Code Playgroud)

第三种风格,在do块内定义它.在这种情况下,func只有在可见之后let; 在第一个...它尚未定义.

foo = do ...
         let func x = x + 1
         mapM_ func aList
         ...
         return aValue
Run Code Online (Sandbox Code Playgroud)

哦,并且好的措施:既然let ... in ...是表达式,你也可以在任何有表达式的地方使用它,来命名一些本地定义.所以这是另一个例子:

foo = do ...
         let func x = x + 1 in mapM_ func aList
         ...
         return aValue
Run Code Online (Sandbox Code Playgroud)

和以前一样,func只在let表达式中可见,在这种情况下,表达式之后是单个表达式,在其他地方.


ham*_*mar 10

另一种选择是使用forM_而不是mapM_翻转参数的顺序.然后,您可以将$运算符与尾随的lambda表达式一起使用,如下所示:

do
  forM_ aList $ \x -> do
    ...

  return aValue
Run Code Online (Sandbox Code Playgroud)