From the department of "It's obvious when you know how". I'd finally got around to working on this issue on Haskerdeux and I'd consolidated the duplicate Curl post requests into one function and had this working code:

curlpost [todays_date, curlpostdata, apiurl, okresponse, username, password] number = withCurlDo $ do
    tdsf <- curlget [todays_date, username, password]
    let itemid = Main.id $ tdsf!!(read (fromJust number)::Int)
    let curlpostfields = if isJust number
        then CurlPostFields ["todo_item["++(show itemid)++"?]"++curlpostdata]
        else CurlPostFields ["todo_item[todo]="++curlpostdata, "todo_item[do_on]="++todays_date]

But I only wanted to do the tdsf and let itemid bits if needed. When I had my three separate (practically duplicate) Curl post requests I could just omit this bit for the function in question, but now I needed some way to handle it conditionally. I had hoped I could do something like this:

curlpost [todays_date, curlpostdata, apiurl, okresponse, username, password] number = withCurlDo $ do
    let curlpostfields = if isJust number
        then CurlPostFields ["todo_item["++(show itemid)++"?]"++curlpostdata]
        else CurlPostFields ["todo_item[todo]="++curlpostdata, "todo_item[do_on]="++todays_date]
        where itemid <- do
            tdsf <- curlget [todays_date, username, password]
            return itemid = Main.id $ tdsf!!(read (fromJust number)::Int)

But that doesn't work and just gives a parse error on input `<-' for the where itemid line. I probably also tried things like:

curlpost [todays_date, curlpostdata, apiurl, okresponse, username, password] number = withCurlDo $ do
    let curlpostfields = if isJust number
        then do 
            tdsf <- curlget [todays_date, username, password]
            itemid = Main.id $ tdsf!!(read (fromJust number)::Int)
            return $ CurlPostFields ["todo_item["++(show itemid)++"?]"++curlpostdata]
        else return $ CurlPostFields ["todo_item[todo]="++curlpostdata, "todo_item[do_on]="++todays_date]

But that gets you:

Couldn't match expected type `CurlOption'
       against inferred type `IO CurlOption'
In the expression: curlpostfields

Which is obvious really as return is an IO type. But I was desperate and clutching at straws. However, thanks to this Stackoverflow question I found out you can do this:

curlpost [todays_date, curlpostdata, apiurl, okresponse, username, password] number = withCurlDo $ do
    curlpostfields <- if isJust number
        then do
            tdsf <- curlget [todays_date, username, password]
            let itemid = Main.id $ tdsf!!(read (fromJust number)::Int)
            return $ CurlPostFields ["todo_item["++(show itemid)++"?]"++curlpostdata]
        else return $ CurlPostFields ["todo_item[todo]="++curlpostdata, "todo_item[do_on]="++todays_date]

Problem solved. I had no idea you could bind if statements in that way. It now seems a shame the where statement option I tried didn't work as that is along the same lines as this binding of the if statement and is a bit more concise.