6 ms·
But I think that the idea of using mathematically pure functions---programming without side effects or mutation---is a/the key idea behind functional programmin
by Chris_Newton 14y ago
But I think that the idea of using mathematically pure functions---programming without side effects or mutation---is a/the key idea behind functional programming.
Indeed, and it is either a blessing or a curse depending on what kind of software you’re trying to write and the sort of situations you’re trying to model.
For most of the programming work I’ve ever done myself, what I’d really like to use is languages that do have concepts like time and side effects, because they’re very useful, but which only use them in controlled ways and when the programmer actually wants them. I’ve often wondered whether such ideas might be elevated to first class concepts within future programming languages, complete with their own rules and specified interactions, just as today we have variables and types and functions, and a language will prevent errors like calling a function with only two values when it expects three or trying to use the value 20 where a string is expected.
For now, I’m hoping that functional programming, in the pure sense, will raise awareness of the potential benefits of controlling side effects rather than allowing them more-or-less arbitrarily as most imperative languages today do. With a bit of luck, the generation of industrial languages in a few years will then borrow ideas that stand the test of time from today’s research into type/effect systems, software transactional memory, and so on, and perhaps we can have something of the best of both worlds.
- tikhonj 14y agoWhat you describe is exactly what Haskell does. You have pure functions by default, but you can have mutable state wherever you want it--it is just constrained to a particular scope by the type system. That is, you can use mutable references, mutable arrays and so on all you want inside a computation, and the compiler will guarantee that none of these references leak outside their scope. Haskell accomplishes this with "state threads" (ST[1]). [1]: http://hackage.haskell.org/packages/archive/base/4.2.0.1/doc/html/Control-Monad-ST.html http://hackage.haskell.org/packages/archive/base/4.2.0.1/doc... Similarly, Haskell has the IO type for containing any side effects at all. This type, as the name implies, can have not only mutable state but also arbitrary I/O--really anything you like. This has some very nice advantages: for example, you can create your own wrapper around the IO type which only exposes some IO operations. You could use this for ensuring that plugins can't do things like delete files, for example. (This is one of the example use cases for Safe Haskell[2], which is worth reading about.) [2]: http://www.haskell.org/ghc/docs/7.4.1/html/users_guide/safe-haskell.html#uses-of-safe-haskell http://www.haskell.org/ghc/docs/7.4.1/html/users_guide/safe-... You can even reify time explicitly, rather than modelling it implicitly with mutable state. This leads to functional reactive programming (FRP[3]), a new and more declarative way to write things like UIs. FRP replaces event and callback oriented programming, fixing much of the spaghetti code common to most UI frameworks. [3]: http://stackoverflow.com/questions/1028250/what-is-functional-reactive-programming http://stackoverflow.com/questions/1028250/what-is-functiona... Really, I think "purely functional" is a very unfortunate term for Haskell from a marketing standpoint. "Purely functional" does not mean that we cannot have side-effects, or mutation, or what have you. It just means that side-effects aren't everywhere by default, and don't implicitly permute your otherwise pretty code.
- deleted 14y ago[deleted]
- Chris_Newton 14y agoI appreciate the comment, but what I have in mind looks very different to the way monads are used in Haskell today. For example, I don’t necessarily want pure functions by default in my idealised programming model. To me, a pure function is just a special case of a function whose effects are controlled and where the resources the function might interact with are readily identifiable, for which the sets of possible effects and interacting resources happen to be empty. Put another way, I don’t see anything wrong, or even inferior or undesirable, with performing a quicksort of an array or some fast matrix computations destructively. However, I’d like my language to make sure I couldn’t accidentally try to use the old data again afterwards (including, for example, in other threads running in parallel). I’d like to be sure that just because my algorithm updates one set of data in-place, it doesn’t also draw a window, block to wait for user input, or kick off a background thread that will reformat my hard drive in half an hour. And in the calling code, I’d like to find out very quickly that just because I created and populated an array over here, and then ran a quicksort that changed it over there, and then printed it out down there, nothing else had any chance to modify it in between. And I’d like to do all of that using syntax that is at least as clean and readable as today’s best languages, please, not the horrors that often seem to result when functional programming languages try to implement equivalent behaviour with realistic heavily structured/monadic values instead of the neat one-integer counter or append-only log that always seems to be used in the tutorial code samples. I suspect that to do that will require a language that provides dedicated, specialised tools to support the new programming model. Sure, you could probably do this sort of thing using monads in Haskell, just as you could do OOP in C, text processing in C++, or write in a functional style in Python, but the results are clumsy compared to using the right tool for the job. I’m not sure that tool exists yet for the kind of programming models I’d like to use, but that’s where I’m hoping the lessons of today’s functional languages and academic research will bear fruit over time.
- jberryman 14y agoYou should really take a look at Haskell. What you describe in your 3rd paragraph is precisely the ST monad. It's true we're still pretty limited in how effects are typed (most effectful stuff still ends up in the "IO sin-bin"), but this is an area of active research and experimentation. This is the way haskell's going, and no one else is even close (afaict).
- jekor 14y agoI agree. Tight, stateful algorithms aren't going to disappear and are harder to reason about (currently) in functional languages. I expect that their implementation and use will shrink over time, in the same way that embedding inline assembler has all but disappeared. I definitely don't expect, or hope, that monads are the final answer to isolating state manipulations, and I agree with a later comment of yours that the IO monad is not granular enough as it is in Haskell. When a large chunk of code ends up being written in the IO monad or in another monad that wraps IO, you miss out on a lot of safety and reasonability that Haskell is supposed to give you. And I've seen that happen (my own projects included).