Haskell and Perl are actually incredibly close in essential ways.
More literal and decoupled languages like Python or Lisp (or C) mostly work from the inside out in a predictable way where the results of a function don't depend on how or where you use it. Sometimes you couple to a global variable or something but usually that's bad practice and you can be careful to avoid it when it isn't necessary.
Haskell and Perl depend on type systems and context to determine what a function is supposed to do. The expression that receives the result of a function has to be interrogated to determine what the function might do and that can continue recursively. Perl uses $ and @ and Haskell gives you a lot more possibilities than that, but most Haskell depends on the local versions of @ and $ because those are the best contexts, as lwall knew. The context focus can be a nightmare or it can be a perfect concise crystal of exactly what you want but it isn't exactly the acme of separation of concerns. Haskell gives you a lot of rope to hang yourself here.
And then there's the way Haskell and Perl both love their proliferation of syntax, mostly sugar, and special symbols that make them look like line noise until you're an insider at the language club. And even then, they can still be line noise but you aren't supposed to admit it.
(Note: I've written Perl and Haskell programs but not used them for significant projects. Mostly I'm stuck with C++ and Javascript for the same reasons you probably are.)
There's an important difference you are missing here, though, which is that even if you don't know what specific type context a function is being used in, you still have some very precise information about what the function may do. For example, you may not know what 'mzero' is going to do in this type context, but you do know that it has some specific properties (e.g. mzero >>= f === mzero) and can extrapolate from there.
You'll have similar problems in dynamic dispatch systems: what does this object do? It could do so many things. In Haskell, we demand that the object always follow a certain set of rules. This is very useful.
More literal and decoupled languages like Python or Lisp (or C) mostly work from the inside out in a predictable way where the results of a function don't depend on how or where you use it. Sometimes you couple to a global variable or something but usually that's bad practice and you can be careful to avoid it when it isn't necessary.
Haskell and Perl depend on type systems and context to determine what a function is supposed to do. The expression that receives the result of a function has to be interrogated to determine what the function might do and that can continue recursively. Perl uses $ and @ and Haskell gives you a lot more possibilities than that, but most Haskell depends on the local versions of @ and $ because those are the best contexts, as lwall knew. The context focus can be a nightmare or it can be a perfect concise crystal of exactly what you want but it isn't exactly the acme of separation of concerns. Haskell gives you a lot of rope to hang yourself here.
And then there's the way Haskell and Perl both love their proliferation of syntax, mostly sugar, and special symbols that make them look like line noise until you're an insider at the language club. And even then, they can still be line noise but you aren't supposed to admit it.
(Note: I've written Perl and Haskell programs but not used them for significant projects. Mostly I'm stuck with C++ and Javascript for the same reasons you probably are.)