8 ms·
> And no one writes pure functional programs. I mean, because they don't exist. This is, both mathematically and practically speaking, incorrect. People write
by jcora 8y ago
> And no one writes pure functional programs. I mean, because they don't exist.
This is, both mathematically and practically speaking, incorrect. People write pure programs all the time.
For example, `f x = putStrLn x` is a pure program. The reason for this is because, despite the name, nothing actually "happens" when this function is evaluated. I suggest you try it: just bind `f "hello world"` to a variable! Nothing happens. Because it's just an immutable value, computed by a pure function with no side effects.
There are situations where IO values get executed, but the crucial point is that computation and execution are logically separated. You can have a structure of IO-producing functions, get a list of IOs from them, filter and modify and reorder them, bind them, process them: they're just data. Pure.
- rujuladanh 8y agoYes, we all know how functional languages work; this is Y Combinator after all. However, that is a pedantic remark and missing OP's point. It is clear OP meant a program as in an entire non-trivial system, not individual functions; even if they are programs themselves. Regardless, when one talks about function purity, it is about the final evaluation, not about partial binding or lazyness.
- jcora 8y agoThis is actually not at all pedantic but a very fundamental, if subtle at first glance, point about purity. Once you start doing more advanced monadic programming it stops being subtle at all. Many people, yes "even on HN", are totally fooled by do notation and the imperative nomenclature, but there is nothing similar. You misunderstand it as well: it has nothing to do with evaluation mode. Idris is eagerly evaluated, for example, and _that function is still pure_! `f x = putStrLn x` gets "finally" evaluated and yes there is still no side effect. It is so evaluated that you can bind it to a variable and apply another function on it. Just like 2^100 is a pure expression, so is `putStrLn "hello"`. > It is clear OP meant a program as in an entire non-trivial system, not individual functions; even if they are programs themselves. It is not clear. Does he mean including the OS and hardware? Because no matter how complex, a pure program is still pure.
- simonh 8y agoOk so run up an embedded OS and application on a system with limited resources so that all the memory is being used. Now run your pure functional program. The system crashes. Using memory is a side effect. Consuming CPU time is a side effect. Heating up the environment and drawing power due to that CPU usage is a side effect[0]. These are not trivial either, actual real systems used for critical activities fall prey to this sort of thing all the time. It just depends on what you are willing to consider as a side effect. [0]https://xkcd.com/1172/ https://xkcd.com/1172/
- jcora 8y agoThat's not what purity refers to! We're talking about a mathematical property of the language itself. The real issue is that people don't understand that `putStrLn "hello"` _is literally just as pure as `2*x`_. They are both like mathematical expressions in that they evaluate to a value and _nothing else_. The name "putStrLn" _suggests_ that this is similar to a print statement but it is emphatically not. You can evaluate it a billion times and nothing gets printed.
- matt_kantor 8y agoHang on a minute. The only difference is that the languages you are talking about have captured "doing I/O" as something that can be statically reasoned about, but not "consuming memory" (for example). From a mathematical perspective, one is part of the axioms while another is not. One could imagine a language where all memory allocation must be done explicitly via a monad, just like how in Haskell all I/O is performed inside an IO monad. If that were the case, you could have additional static guarantees about how memory is used. That doesn't mean that languages which don't do this are somehow inherently "impure"; they are simply "pure with respect to a certain set of axioms" (which don't talk about memory usage). "The system crashed" example is fun too. All pure functions must return a value, right? Well, that's obviously not gong to be the case if the computer blows up halfway through executing a pure function. "Blowing up" might not be something your type system talks about—Haskell does to some degree (with _|_ inhabiting every type), but Idris for example has total functions which at runtime could most definitely be interrupted by a sudden explosion. They are "total" only with respect to a set of axioms which imply an execution model where computers do not explode mid-program.