Если это для чего-то простого, и это всего лишь несколько функций, которые делают это, возможно, в IO, я бы просто сделал тип IO (Maybe User)
.
Если это шаблон, который простирается через вашбиблиотеке, я бы дал полуабстрактное имя монаде tfm-стека:
type Request = MaybeT IO
findById :: ID -> Request User
... или даже
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
newtype Request a = Request (runRequest :: MaybeT IO a)
deriving (Functor, Applicative, Monad)
Создание подписи ID -> MaybeT IO User
не оченьхорошо: преобразователь помогает, только если вы выполняете целую кучу действий в этой монаде, но в этом случае всегда выписывание MaybeT IO
нарушает принцип СУХОГО.