I think I much prefer Haskell DSLs over Lisp macros as the basis for APIs in foreign code. That might be due to my relative inexperience with Lisps, but macros just seem to make all the bad aspects of dynamically typed langues much worse. Looking at some piece of code in isolation, not only is it often impossible to tell what is the type/shape of data that are coming in (as is common with dynamic type systems) but with macros added to the mix I also can't tell what the control flow is. So to understand what a single piece of code is doing, I find myself chasing for hints that are scattered throughout the entire codebase.
Contrast this to Haskell's use of DSLs – although they really can be quite dense sometimes, I feel like, when I get stuck, I can always just dig into the documentation on Hackage, and figure out things from the type definitions (even when explanations in docs are lacking). Though it does require being comfortable with the abstractions being used (monads and such). Rust is similar in this manner but to a lesser extent.
But again, maybe the macro critique stems from my inexperience with them.
Contrast this to Haskell's use of DSLs – although they really can be quite dense sometimes, I feel like, when I get stuck, I can always just dig into the documentation on Hackage, and figure out things from the type definitions (even when explanations in docs are lacking). Though it does require being comfortable with the abstractions being used (monads and such). Rust is similar in this manner but to a lesser extent.
But again, maybe the macro critique stems from my inexperience with them.