使用列表中的位置

时间:2018-01-03 11:10:54

标签: haskell

有没有办法在列表语法中使用where表达式?我想像这样的东西会起作用:

foo = [i where i = 1]

但编译产量:

  

错误:输入'where'

时解析错误

可以在列表中使用let ... in

foo = [let i = 1 in i]

所以我假设wherelet表现为不同的句法结构?

我知道可以这样做:

foo = [i] where i = 1

...但是对于更复杂的列表,ii = 1之间的距离太远而无法清楚 - 请参阅下面的上下文部分并想象更多的测试用例, testGroup本身嵌套在列表中。

上下文

我试图编写一个可读的测试用例时遇到了这个问题:

testGroup "toInput"
[
    testProperty "toInput '*'" (forAll others conversionFails)
            where others = arbitrary `suchThat` (\c -> c `notElem` exclChars)
                  conversionFails c = toInput c == Nothing
]

等同于let并不满足于阅读imo(更具体地说,当被其他测试用例包围时,testProperty不会与他们进行相同的缩进更难以遵循)。

testGroup "toInput"
[
    let others = arbitrary `suchThat` (\c -> c `notElem` exclChars)
        conversionFails c = toInput c == Nothing
    in
        testProperty "toInput '*'" (forAll others conversionFails)
]

4 个答案:

答案 0 :(得分:4)

Haskell Wiki article says

类似
  

重要的是要知道let ... in ...是一个表达式,也就是说,只要允许表达式就可以写。相比之下,where   绑定到周围的句法结构,就像函数定义的模式匹配行一样。

简而言之,where绑定到函数声明的子句,而let更多地局限于表达式。如果您编写where,则整个子句都可以看到它,例如:

f a | a > 0 = g b b
    | otherwise = b
    where b = g a a

所以这里where对于两名警卫是可见的,let更局部地作用于范围。如果您撰写let y = f x in y * y,则y部分in ...可见。例如,我们可以写:

Prelude> let a = 4 in (let a = 2 in a) + a
6

因此,内部a2,而外部为4。这可能最终会让人感到困惑。如果我们在where子句中定义具有相同名称的变量,则会导致名称冲突。

如果您的代码示例是单个函数,您当然可以将其移出列表定义,例如:

foo exclChars = 
  testGroup "toInput" [testProperty "toInput '*'" (forAll others conversionFails)]
  where others = arbitrary `suchThat` (`notElem` exclChars)
        conversionFails = isNothing . toInput

答案 1 :(得分:2)

[1 | 1==2]也是列表理解。 1==2是布尔表达式

在您的示例foo = [let i = 1 in i]中,let i = 1 in i也是一个表达式。

确实wherelet不同。 let形成一个表达式,但where不表达 - 它是定义(a = b where ...)的一部分。

区别在于,where定义的变量可用于定义的 guards ,而let位于=符号的右侧

对于您的问题,只需在]之前移动where,它就会成为定义的一部分。

答案 2 :(得分:1)

您可能期待使用列表推导。在列表推导中,您可以使用|,这意味着,您可以说[ i | i <- [1] ]。因此,您可以按如下方式使用它们:[ ... | others <- [suchThat arbitrary (\c -> notElem c exclChars)]在您的示例中。

答案 3 :(得分:1)

我不确定你为什么要这个特定的列表理解,但是这样可行,你可以在GHCi中尝试:

> [ i | let i=1 ]
[1]

您无法在列表理解中使用where来实现此效果。