Haskell where子句语法在do块中

时间:2012-12-30 17:20:41

标签: haskell syntax where-clause

我正在尝试重构Haskell中mapM_块内的do函数调用。我想将lambda提取到(本地)命名函数,以使代码更具可读性。

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

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

  return aValue

我想将其更改为

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

  return aValue

但我在return aValue行收到语法错误。我的实际lambda更复杂:-),但我确实尝试使用相同的lambda来确保它不是lambda代码中的问题。

如何重写此代码?我应该使用let ... in吗?

3 个答案:

答案 0 :(得分:31)

这里有三种相似(但不同)的定义方法:

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

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

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

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

第一种样式,其中funcfoo中的任何位置都可见,包括where子句中定义的任何其他内容:

foo = do ...
         mapM_ func aList
         ...
         return aValue
  where func x = x + 1

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

foo = let func x = x + 1 
      in do 
         ...
         mapM_ func aList
         ...
         return aValue

第三种风格,在do区块内定义它。在这种情况下,func仅在let之后可见;在第一个...中,它还没有定义。

foo = do ...
         let func x = x + 1
         mapM_ func aList
         ...
         return aValue

哦,好的方法:由于let ... in ...是一个表达式,你也可以在任何有表达式的地方使用它来命名一些本地定义。所以这是另一个例子:

foo = do ...
         let func x = x + 1 in mapM_ func aList
         ...
         return aValue

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

答案 1 :(得分:10)

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

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

  return aValue

答案 2 :(得分:3)

你的where不应该在功能的最后?

像这样:

function aList aValue = do
    mapM_ func aList
    return aValue
    where func x = x + 1