I have the following code snippet, which kinda works:
launchTask :: (DeviceRepo m) => TaskSpec -> m (Maybe Task)
launchTask taskSpec@TaskSpec { taskSpecImage = image
, taskSpecRequirement = requirement
} = do
mayDevice <- getDeviceMatchingRequirement requirement
case mayDevice of
Nothing -> return Nothing
Just device -> do
mayContainer <- createContainer device requirement
case mayContainer of
Nothing -> return Nothing
Just container ->
return $
Just
Task
{ taskName = pack image
, taskStatus = TaskStatusRunning
, taskSpec = taskSpec
, taskContainerId = containerId container
}
However, I feel that this is not very idiomatic. What's the right way to stack the main calculation (from DeviceRepo m) and perhaps a Maybe monad so that if any of the values are missing then Nothing is instantly returned?
Edit: My attempt with MaybeT, but the type doesn't match
launchTask2 :: (DeviceRepo m) => TaskSpec -> m (Maybe Task)
launchTask2 taskSpec@TaskSpec { taskSpecImage = image
, taskSpecRequirement = requirement
} = runMaybeT launcher
where
launcher :: MaybeT m Task
launcher =
getDeviceMatchingRequirement requirement >>= \device ->
createContainer device requirement >>= \container ->
return
Task
{ taskName = pack image
, taskStatus = TaskStatusRunning
, taskSpec = taskSpec
, taskContainerId = containerId container
}
• Couldn't match expected type ‘Device’
with actual type ‘Maybe Device’
• In the first argument of ‘createContainer’, namely ‘device’
In the first argument of ‘(>>=)’, namely
‘createContainer device requirement’
In the expression:
createContainer device requirement
>>=
\ container
-> return
Task
{taskName = pack image, taskStatus = TaskStatusRunning,
taskSpec = taskSpec, taskContainerId = containerId container}
|
58 | createContainer device requirement >>= \container ->
| ^^^^^^
You are probably looking for the MaybeT monad transformer from the transformers package:
import Control.Monad.Trans.Maybe(MaybeT(MaybeT))
launchTask' :: DeviceRepo m => TaskSpec -> MaybeT m Task
launchTask' taskSpec@TaskSpec { taskSpecImage = image, taskSpecRequirement = requirement } = do
device <- MaybeT (getDeviceMatchingRequirement requirement)
container <- MaybeT (createContainer device requirement)
return Task
{ taskName = pack image
, taskStatus = TaskStatusRunning
, taskSpec = taskSpec
, taskContainerId = containerId container
}
This is thus a function MaybeT m Task, you can use runMaybeT to transform the MaybeT m a into an m (Maybe a):
import Control.Monad.Trans.Maybe(runMaybeT)
lanchTask :: DeviceRepo m => TaskSpec -> m (Maybe Task)
launchTask = runMaybeT . lanchTask'
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With