0

Here's the working code I have:

DataSet myDataSet = new DataSet();
mySqlDataAdapter.Fill(myDataSet);
DataTable positionData = myDataSet.Tables["Table"];
if (siteData.Rows.Count > 0)
{
    positionDV = string.Join<object>(", ",
        from r in siteData.Rows.OfType<DataRow>() select r[1]);
}
else
{
    positionDV = "";
}

The content of positionDV looks like this "14, 47, 5, , 11" etc. where there is a blank space for each NULL value in the database.

What I would like to achieve is that the values which are NULL are actually written to the string as NULL. So the above example would look like "14, 47, 5, null, 11".

positionDV is just one string shown for brevity, in reality there are dozens per dataset, with close to 100,000 values each.

What I am looking for is a way to insert null instead of a space. Would it be more efficient to create a conditional during the string.Join (and if so, how would I do that?), or would it be more efficient to just create the string as is and then create a separate assignment to do that like so:

positionDV += positionDV.replace(", ,", ", null,");

How do you stack two ErrorT monad transformers on top of each other?

Let's say I have these two functions:

errorm :: ( MonadError String m ) => Bool ->  m Int
errorm cond = if cond then return 1 else throwError "this is an error"

errorms :: ( MonadError String m ) => Bool ->  m String
errorms cond = if cond then return "works" else throwError "does not work"

As you can see, one returns a string in the safe case, while the other returns an int

I now want to use them together within another monad. Trivially:

errErr :: MonadError String m => Bool -> Bool -> m (Int, String)
errErr b1 b2 = do
    a <- errorm b1 
    b <- errorms b2
    return (a,b)

The function signature here is derived by the GHC, and I am not sure how to use this function. I tried this:

runErrorT ( runErrorT ( errErr1 True True ) )  -- should give me (Right 1, Right "works")

But instead it gives me:

Ambiguous type variable `e0' in the constraint:
(Error e0) arising from a use of `errErr1'
Probable fix: add a type signature that fixes these type variable(s)
In the first argument of `runErrorT', namely `(errErr1 True True)'
In the first argument of `runErrorT', namely
  `(runErrorT (errErr1 True True))'
In the expression: runErrorT (runErrorT (errErr1 True True))

In general, this is just one instance of my problem. I feel like I am not grasping how exactly to stack two monadT that are of the same class, but have different type parameters. Another example might be stacking the pair of a functions:

f :: ( MonadState Int m ) => m ()
g :: ( MonadState String m ) => m ()

---------------------------------------------------- Update ----------------------------------------------------

Per Daniel's comment below, I added a concrete instance of functions f and g from above. But thanks to Tikhon's answer, I think I figured it out.

type Counter = Int
type Msg     = String

incr :: (MonadState Counter m) => Counter -> m ()
incr i = modify (+i)

addMsg :: ( MonadState Msg m ) => Msg -> m()
addMsg msg = modify ( ++ msg )

incrMsg:: (MonadTrans t, MonadState Msg m, MonadState Counter (t m)) => t m ()
incrMsg = do 
    lift . addMsg $ "one"
    incr 1
    return ()

incrMsgt = runIdentity $ runStateT ( runStateT incrMsg 1 ) "hello" :: (((), Int), String)
4

1 に答える 1