Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nested `do` blocks in Haskell

Tags:

haskell

I'm trying to write a function in Haskell which checks for some things and then recurses based on some minimal user input. In order to do that I think I have to use do blocks.

cip :: [Argument] -> [Argument] -> Bool -> Bool -> IO()
cip (a:args) pargs burden gameover = do
    let nasko = a:pargs
    putStrLn (getPremise a)
    let newgraph = Carneades.mkArgGraph nasko
    let newcaes = (CAES (newgraph,audience2,assStandarts)) 
    let answer = (acceptable (mkProp (getPremise a)) newcaes )
    print answer
    if(answer==True) 
    then (cip args nasko burden gameover) 
    else do
        print "One of the arguments is not proved. Here are the premises that need proving"
        print (propsForFixing newcaes a)
        print "Let's see what you have for the first Propositon"
        --add an if to check if no applicable arguments.
        print (argumentScanHelp (head (propsForFixing newcaes a)) args)
        print "\n Would you like me to apply the firt one? Y/N"
        choice <- getLine
        if(choice=="Y") then do print "applying the argument"
                                let applicabee = head (argumentScanHelp (head (propsForFixing newcaes a)) args)
                                print "Argument targeted"
                                let newargs = delete applicabee args
                                let newpargs = applicabee:nasko
                                print "Argument applied sucsessfuly. Recusing again"
                                (cip newargs newpargs burden gameover)
return()

It hurts my eyes just by looking at it, but that's do blocks for you. Everything up to the third do block is okay. But then on this line:

        if(choice=="Y") then do print "applying the argument"
                                let applicabee = head (argumentScanHelp (head (propsForFixing newcaes a)) args)

The complier starts crying:

Main.hs:209:73: parse error on input `let'

Tried a all kinds of different indentations but I can't seem to get it to work. I don't want to use separate functions, because that means I'll have to pass a lot of arguments around constantly.

Can anyone help me get it right? Also an explanation of what exactly the specifications for nested do block are would be greatly appreciated.

like image 739
Atanas Bozhkov Avatar asked Dec 04 '12 00:12

Atanas Bozhkov


1 Answers

The cause of the error I believe is the misuse of the if expression. You use it as if it were an if statement that exists in most imperative languages. Simply put there must always be an else.

However, in do blocks it makes sense to "not have an else", something like an if statement without an else. Luckily the Control.Monad module will provide you with a function for exactly that:

import Control.Monad (when)

(...)

when (choice=="Y") $ do print "applying the argument"
                        let applicabee = ...

You seem to already use nested do blocks in the correct way which is good, which basically is that you must indent properly.

PS. Also make sure your last return () is indented like the rest of your code! DS.

like image 52
Tarrasch Avatar answered Oct 17 '22 20:10

Tarrasch