I've certainly learned more Maths as a result of learning Haskell, but I don't think the amount of Maths is vastly more than other languagues; or rather, other languages hide the Maths, either on purpose or by accident.
For example, Haskell uses terms like "Monad", "Monoid", "Functor", etc. which are Mathematical ideas, but as far as the language is concerned they're just interfaces (APIs). OO APIs can get just as gnarly, so if someone's comfortable with design patterns like inversion-of-control containers, dependency-injection mocking frameworks, factory factories, etc. then functional programming ideas are "different" but not necessarily "harder". Like all fields, there's a progression of ideas from simplistic, to powerful, to brain-bending, which everyone can scale at their own pace.
> ...the real problem for me seems to be monads. Without having /some/ kind of side effects, you cannot write an even remotely useful program, and I never really got them.
Whilst that's technically true, all it takes is one side-effect to have a useful program. It's perfectly acceptable to ignore monads and side-effects in all of your code, then write a simple "main" definition which plugs them together. In fact, that's the encouraged way of programming in Haskell! If you're playing around in a commandline, like GHCi, then you don't even need a "main" function at all.
If you're really struggling, you can often copy/paste a "main" which works for you. A trivial one is "print foo", but even in more realistic examples it's possible. To read and write over stdio, you can write the whole thing with pure functions, treat your argument as stdin and your return value as stdout, then do:
main = interact myFunction
The only time monads are actually required is when you need to choose between different side-effects, depending on the result of a previous side-effect. For example, if you write to a file, and the filename depends on the contents of another file:
main = do name <- readFile "I_CONTAIN_THE_NAME"
writeFile name myString
When side-effects don't depend on each other, you can use simpler alternatives to Monad, eg. Applicative:
Or, when you only need one side-effect, you don't need any of those interfaces at all:
main = print "Hello world"
> I have a feeling that an idiomatic Haskell program would make far heavier use of the type system to model your problem than even extreme examples of object-oriented design
The way I see it, if you're learning Haskell and you're tempted to throw an exception, you're probably using the wrong type. Exceptions can be useful, and there are advanced Haskell users who make regular use of them, but nowhere near the extent that they're used outside Haskell. Many "exceptional circumstances" simply never arise if you use stronger types.
I've certainly learned more Maths as a result of learning Haskell, but I don't think the amount of Maths is vastly more than other languagues; or rather, other languages hide the Maths, either on purpose or by accident.
For example, Haskell uses terms like "Monad", "Monoid", "Functor", etc. which are Mathematical ideas, but as far as the language is concerned they're just interfaces (APIs). OO APIs can get just as gnarly, so if someone's comfortable with design patterns like inversion-of-control containers, dependency-injection mocking frameworks, factory factories, etc. then functional programming ideas are "different" but not necessarily "harder". Like all fields, there's a progression of ideas from simplistic, to powerful, to brain-bending, which everyone can scale at their own pace.
> ...the real problem for me seems to be monads. Without having /some/ kind of side effects, you cannot write an even remotely useful program, and I never really got them.
Whilst that's technically true, all it takes is one side-effect to have a useful program. It's perfectly acceptable to ignore monads and side-effects in all of your code, then write a simple "main" definition which plugs them together. In fact, that's the encouraged way of programming in Haskell! If you're playing around in a commandline, like GHCi, then you don't even need a "main" function at all.
If you're really struggling, you can often copy/paste a "main" which works for you. A trivial one is "print foo", but even in more realistic examples it's possible. To read and write over stdio, you can write the whole thing with pure functions, treat your argument as stdin and your return value as stdout, then do:
The only time monads are actually required is when you need to choose between different side-effects, depending on the result of a previous side-effect. For example, if you write to a file, and the filename depends on the contents of another file: When side-effects don't depend on each other, you can use simpler alternatives to Monad, eg. Applicative: Functor: Or, when you only need one side-effect, you don't need any of those interfaces at all: > I have a feeling that an idiomatic Haskell program would make far heavier use of the type system to model your problem than even extreme examples of object-oriented designThe way I see it, if you're learning Haskell and you're tempted to throw an exception, you're probably using the wrong type. Exceptions can be useful, and there are advanced Haskell users who make regular use of them, but nowhere near the extent that they're used outside Haskell. Many "exceptional circumstances" simply never arise if you use stronger types.