Search code examples
haskelldsltemplate-haskell

Bind monadic variables over several functions


I'm interested in getting as close as possible to the following syntax. TH is just fine by me.

bootapplication :: IO ()
bootapplication = do
  clientA <- newChan :: IO (Chan AMsg)
  clientB <- newChan :: IO (Chan BMsg)
  ...
  magicHappens


doSomething :: SomeSortaMonadTOnIO ()
doSomething = do
  writeChan clientA aMsg
  writeChan clientB bMsg

I suppose the following is acceptable

main = do
    clientA <- newChan :: IO (Chan [Char])
    clientB <- newChan :: IO (Chan Whatever)
    let a = putStrLn . (++) "a"
    let moof = do
--      b "hello"
        a "hi"
--      d "meh"
        readChan clientA
        return ()
    let b = putStrLn . (++) "b"
    let d = putStrLn . (++) "c" 
    return ()

But the commented lines are unacceptable since a let binding only works going forward. How do I hammer and duct tape ghc into letting me do this?

Edit:

Here's the syntax I settled on

main = do
    clientA <- newChan :: IO (Chan [Char])
    clientB <- newChan :: IO (Chan Whatever)
    let {

a :: [Char] -> IO ()
;a = putStrLn . (++) "a"

;moof :: IO ()
;moof = do 
    a "a"
    b "b"

;b :: [Char] -> IO ()
;b = putStrLn . (++) "b"

;d :: [Char] -> IO ()
;d = putStrLn . (++) "c"


}
    moof
    return ()

Solution

  • Answering your exact question, just unite those lines in a single let block:

    main = do
      clientA <- newChan :: IO (Chan [Char])
      clientB <- newChan :: IO (Chan Whatever)
      let 
        a = putStrLn . (++) "a"
        moof = do
          b "hello"
          a "hi"
          d "meh"
          readChan clientA
          return ()
        b = putStrLn . (++) "b"
        d = putStrLn . (++) "c" 
      return ()
    

    Alternatively you can use where, which is more conventional to store function definitions in, as it is in your case:

    main = do
      clientA <- newChan :: IO (Chan [Char])
      clientB <- newChan :: IO (Chan Whatever)
      let 
        moof = do
          b "hello"
          a "hi"
          d "meh"
          readChan clientA
          return ()
      return ()
      where
        a = putStrLn . (++) "a"
        b = putStrLn . (++) "b"
        d = putStrLn . (++) "c"
    

    From the above code it's easy to trace that moof will in fact never get executed, because let a = b inside a do block is just a sugar for a <- return b. So I guess what you intended in fact was the following:

    main = do
      clientA <- newChan :: IO (Chan [Char])
      clientB <- newChan :: IO (Chan Whatever)
      moof <- do
        b "hello"
        a "hi"
        d "meh"
        readChan clientA
        return ()
      return ()
      where
        a = putStrLn . (++) "a"
        b = putStrLn . (++) "b"
        d = putStrLn . (++) "c"