Search code examples
haskellletdo-notation

Different let in for lines in do block


I want to create some tests with varying values, using hspec. I wrote the following code which does not compile but give an idea of what I am aiming at:

spec :: Spec
spec = do
    describe "productOneLine" $ do
        let
            inVector = Data.Vector.replicate 0 0
            inInteger = 3
            outVector = Data.Vector.replicate 1 0
        in
            it "must manage empty vector" $ productOneLine inVector inInteger `shouldBe` outVector
        let
            inVector = Data.Vector.fromList [2, 4, 5]
            inInteger = 4
            outVector = Data.Vector.fromList [9, 6, 1, 2]
        in
            it "must multiply a vector by an integer" $ productOneLine inVector inInteger `shouldBe` outVector

How can I create different sets of inVector, inInteger et outVector for each ligne beginning with it ?


Solution

  • Assuming you're getting the error:

    parse error on input `in'
    

    the problem is just indentation, as per @n.`pronouns'm.'s comment.

    In most cases, a let block can be written with the let and in keywords lining up:

    foo a b = let a2 = a*a
                  b2 = b*b
              in a2 + b2
              ^
              `- let and in starting at same column
    

    In fact, the in can be less indented than the let, it just needs to be indented more than the foo:

    foo a b = let a2 = a*a
                  b2 = b*b
      in a2 + b2
    

    However, in a do block, an in-less let statement is allowed:

    main = do
      let s = "Hello"
      putStrLn s
    

    If you try to write:

    main = do
      let s = "Hello"
      in PutStrLn s
    

    the let s = "Hello" is parsed as a let statement, and the in PutStrLn s is parsed as a second do statement, with invalid syntax as it starts with the reserved word in.

    You can write:

    main = do
      let s = "Hello" in
        putStrLn s
    

    or:

    main = do
      let s = "Hello"
        in putStrLn s
    

    or:

    main = do
      let s = "Hello"
        in 
        putStrLn s
    

    In each case, the indention will cause the entire expression let ... in ... to be parsed as a single expression, which is itself a valid do-statement. Combining two such statements is easy enough:

    main = do
      let s = "Hello"
        in
        putStrLn s
      let s = "Goodbye"
        in
        putStrLn s