(But monads in the form of a parser combinator like Parsec can implement external DSLs, even an external DSL like Perl 6...) Monads and DSLs are both applications of metaprogramming because each of the two effectively transforms minimal code into a complete form for execution. In fact, as monad tutorials instruct, Haskell's "do-notation" is syntax sugar, i.e. a DSL, for using monads...
— Art Vandalay, of metaprogramming, monads, DSLs
Most of the rest of the post is useful, but the paragraph from which I took this quote goes (warning: intentional pun) way off the rails.
To start, it's difficult to describe an internal language feature as a domain-specific language, unless that feature is useful when independent of the host language. Perl regular expressions qualify as a DSL, but scoping declarators do not.
To nitpick, what precisely is the domain to which Perl 6 is specific? "General purpose programming languages"? The general is the enemy of the specific, or at least the enemy general.
I'm not sure it's useful to talk about the way that monads transform code into "a complete form for execution" in this context. That line of reasoning eventually equates syntax with DSLishness, and as you can see, that "eventually" has a very short period. While I agree that metaprogramming offers the opportunity for code transformation (though not always to the degree found in homoiconic languages, as Art mentions), effectively all code transformations are part of either an algorithm (in the metaprogramming sense) or the compiler (in the syntactic sugar sense). In the context of how compilers and languages work, that transformation is highly appropriate. In the context of language syntax alone, it's tautological -- the compiler supports the language's syntax. That's what compilers do.
This is my quibble with the quoted paragraph, and especially the parenthetical note. A parser -- Parsec -- can parse text, including programming languages.
That's what parsers do, just like subroutines let you name operations in your program after actions in the problem domain, just like namespaces and classes let you categorize, group, model, and name entities in your program after entities and concepts in your problem domain, and language features allow you to describe your intent algorithmically in a precise and organized fashion.
You can exploit corner cases in the language's parser, but as long as you depend on the host language's compiler to transform your code into the proper form for its execution model, you're writing APIs.That's what (post-structured programming) programming languages are for. There is no shame in that. Of course, there should be shame in gratuitous parser abuse, especially when the result is barely-literate pidgin that barely nods to the language of the problem domain. Then again, I care about maintainability and correctness and screechingly obvious code, not "Hey test fixture User is some description do end!"
(For the ultimate in fun, ask yourself "From what domain did the Haskell designers take the word monad and, if monads are truly a DSL in Haskell (rather than an intrinsic language idiom), what does that imply about their problem domain?")