Skip to main content
added 10 characters in body
Source Link
cjs
  • 783
  • 4
  • 8

My (limited) understanding of functional programming is that state/side effects should be minimised and kept separate from stateless logic.

That's not just functional programming; that's usually a good idea in any language. If you do unit testing, the way you split apart x = read_file(), y = convert(x) and write_file(y) comes perfectly naturally because, despite convert() being by far the most complex and largest part of the code, writing tests for it is relatively easy: all you need to set up is the input parameter. Writing tests for read_file() and write_file() is quite a bit harder (even though the functions themselves are almost trivial) because you need to create and/or read things on the file system before and after calling the function. Ideally you'd make such functions so simple that you feel comfortable not testing them and thus save yourself a lot of hassle.

The difference between Python and Haskell here is that Haskell has a type checker that can prove that functions have no side effects. In Python you need to hope that nobody's accidentally dropped in a file-reading or -writing function into convert() (say, read_config_file()). In Haskell when you declare convert :: String -> String or similar, with no IO monad, the type checker will guarantee that this is a pure function that relies only on its input parameter and nothing else. If someone tries to modify convert to read a config file they will quickly see compiler errors showing that they'd be breaking the purity of the function. (And hopefully they'd be sensible enough to move read_config_file out of convert and pass its result into convert, maintaining the purity.)

My (limited) understanding of functional programming is that state/side effects should be minimised and kept separate from stateless logic.

That's not just functional programming; that's usually a good idea in any language. If you do unit testing, the way you split apart read_file(), convert() and write_file() comes perfectly naturally because, despite convert() being by far the most complex and largest part of the code, writing tests for it is relatively easy: all you need to set up is the input parameter. Writing tests for read_file() and write_file() is quite a bit harder (even though the functions themselves are almost trivial) because you need to create and/or read things on the file system before and after calling the function. Ideally you'd make such functions so simple that you feel comfortable not testing them and thus save yourself a lot of hassle.

The difference between Python and Haskell here is that Haskell has a type checker that can prove that functions have no side effects. In Python you need to hope that nobody's accidentally dropped in a file-reading or -writing function into convert() (say, read_config_file()). In Haskell when you declare convert :: String -> String or similar, with no IO monad, the type checker will guarantee that this is a pure function that relies only on its input parameter and nothing else. If someone tries to modify convert to read a config file they will quickly see compiler errors showing that they'd be breaking the purity of the function. (And hopefully they'd be sensible enough to move read_config_file out of convert and pass its result into convert, maintaining the purity.)

My (limited) understanding of functional programming is that state/side effects should be minimised and kept separate from stateless logic.

That's not just functional programming; that's usually a good idea in any language. If you do unit testing, the way you split apart x = read_file(), y = convert(x) and write_file(y) comes perfectly naturally because, despite convert() being by far the most complex and largest part of the code, writing tests for it is relatively easy: all you need to set up is the input parameter. Writing tests for read_file() and write_file() is quite a bit harder (even though the functions themselves are almost trivial) because you need to create and/or read things on the file system before and after calling the function. Ideally you'd make such functions so simple that you feel comfortable not testing them and thus save yourself a lot of hassle.

The difference between Python and Haskell here is that Haskell has a type checker that can prove that functions have no side effects. In Python you need to hope that nobody's accidentally dropped in a file-reading or -writing function into convert() (say, read_config_file()). In Haskell when you declare convert :: String -> String or similar, with no IO monad, the type checker will guarantee that this is a pure function that relies only on its input parameter and nothing else. If someone tries to modify convert to read a config file they will quickly see compiler errors showing that they'd be breaking the purity of the function. (And hopefully they'd be sensible enough to move read_config_file out of convert and pass its result into convert, maintaining the purity.)

Source Link
cjs
  • 783
  • 4
  • 8

My (limited) understanding of functional programming is that state/side effects should be minimised and kept separate from stateless logic.

That's not just functional programming; that's usually a good idea in any language. If you do unit testing, the way you split apart read_file(), convert() and write_file() comes perfectly naturally because, despite convert() being by far the most complex and largest part of the code, writing tests for it is relatively easy: all you need to set up is the input parameter. Writing tests for read_file() and write_file() is quite a bit harder (even though the functions themselves are almost trivial) because you need to create and/or read things on the file system before and after calling the function. Ideally you'd make such functions so simple that you feel comfortable not testing them and thus save yourself a lot of hassle.

The difference between Python and Haskell here is that Haskell has a type checker that can prove that functions have no side effects. In Python you need to hope that nobody's accidentally dropped in a file-reading or -writing function into convert() (say, read_config_file()). In Haskell when you declare convert :: String -> String or similar, with no IO monad, the type checker will guarantee that this is a pure function that relies only on its input parameter and nothing else. If someone tries to modify convert to read a config file they will quickly see compiler errors showing that they'd be breaking the purity of the function. (And hopefully they'd be sensible enough to move read_config_file out of convert and pass its result into convert, maintaining the purity.)