You can think a monad defines a DSL. Let's take for example the Rand[0] monad:
type Rand g = RandT g Identity
newtype RandT g m a = ...
-- with
runRandT :: (Monad m, RandomGen g) => RandT g m a -> g -> m (a, g)
newtype MyType = Rand StdGen
-- now you can define
intGreaterThan :: Integer -> MyType Integer
intGreaterThan = ...
randomName :: Integer -> MyType String
randomName length = ...
-- an finally convine the two above
nRandomNames :: Integer -> Integer -> MyType [String]
nRandomNames length n
| n <=0 = return []
| otherwise = do
tailNames <- nRandomNames (n-1)
headName <- randomName length
return (headName:tailNames)
These functions of type `...->MyType a` can be viewed as a DSL where the Random generator state is abstracted away.[0]hackage.haskell.org/package/MonadRandom-0.3/docs/Control-Monad-Random.html