I have been trying to wrap my head around functional programming for a while now? I have looked up lambda calculus, LISP, OCML, F# and even combinatorial logic but the main problem I have is how do you do things that require side effects like (interacting with a user, communicating with a remote service, or even handle simulating using random sampling) without violating the fundamental premise of pure functional programming which is, that for a given input the output is deterministic? I hope I am making sense, if not I welcome any attempts to properly educate me. Thanks in advance.
相关问题
- Relation between Function1 and Reader Monad
- scala passing function with underscore produces a
- Combining n vectors into one vector of n-tuples
- Improve this code by eliminating nested for cycles
- Redefine list monad instance
相关文章
- Is there something like the threading macro from C
- Learning F#: What books using other programming la
- Creating a list of functions using a loop in R
- When to use interfaces, and when to use higher ord
- Functors in Ocaml
- Java Lambda Referencing Enclosing Object: Replace
- Are 'currying' and 'composition' t
- Mock side effect only X number of times
The only completely pure functional language I know of is the template system in C++. Haskell takes second place by making the imperative portions of the program explicit.
In Haskell the program has mutable state, but functions (almost always) don't. You keep like 99% percent of program pure, and only the portion that interacts with the outside world is impure. Therefore when you are testing a function, you know there are no side effects. Pure core, with an impure shell.
Even if you don't use it in your work, learning one or more functional programming languages is a great way to learn to think differently and gives you a toolkit of alternative approaches to problems (it can also frustrate you when you can't do something as neat and clean as a functional approach in other languages).
And it made me a better at writing XSL stylesheets.
Haskell is a pure functional programming language. In Haskell all functions are pure (i.e. they always give the same output for the same inputs). But how do you handle side-effects in Haskell? Well, this problem is beautifully solved through the use of monads.
Taking I/O as an example. In Haskell every function that does I/O returns an IO computation, i.e. a computation in the IO monad. So, for instance, a function that reads an int from the keyboard, instead of returning an int, returns an IO computation that yields an int when it is run:
Because it returns an I/O computation instead of an
Int
, you cannot use this result directly in a sum, for example. In order to access theInt
value you need to "unwrap" the computation. The only way to do this is to use the bind function (>>=
):Because this also returns an IO computation, you always end up with an I/O computation. This is how Haskell isolates side-effects. The IO monad acts as an abstraction of the state of the real world (in fact under the covers it is usually implemented with a type named
RealWorld
for the state part).Interacting with a user and communicating with a remote service do require some sort of non-functional part to your software.
Many "functional languages", (like most Lisps) are not purely functional. They still let you do things with side-effects, though side-effecty things are "discouraged" in most contexts.
Haskell is "purely functional" but still lets you do non-functional things via the IO monad. The basic idea is that your purely functional program emits a lazy data structure which is evaluated by a non-functional program (which you don't write, it's part of the environment). One could argue that this data structure itself is an imperative program. So you're sort of doing imperative meta-programming in a functional language.
Ignoring which approach is "better", the goal in both cases is to create a separation between the functional and non-functional parts of your programs, and to limit the size of the non-functional parts as much as possible. The functional parts tend to be more reusable, testable, and easier to reason about.
The way Haskell does it is by using monads see wikipedia and the explanation by Haskell on their page.
Basically the idea is that you do not get rid of the IO monad. My understanding is that you are able to chain functions that unwrap an IO monad and execute that function. But you are not able to remove the IO monad altogether.
Another example using monads that is not directly tied to IO is the Maybe Monad. This monad is 'unwrappable' in contrary to the IO monad. But it is easier to explain the use of monads using the Maybe monad. Let's assume you have the following function.
now you can call
wrap (Just 4) (5+)
which will returnJust 9
.The idea of the IO-monad is that you can use functions like (+5) on the internal type. The monad will assure that the functions will be called in serial, because every function is chained with the wrapping IO-monad.
Given that most programs have some effects on the outside world (writing to files, modifying data in a database...) programs as whole are rarely side-effect free. Outside of academic exercises, there is no point in even trying.
But programs are assembled out of building blocks (subroutine, function, method, call it what you want), and pure functions make for very well-behaved building blocks.
Most functional programming languages do not require functions to be pure, although good functional programmers will try to make as many of their functions pure as is feasible and practical, in order to reap the benefits of referential transparency.
Haskell goes further. Every part of a Haskell Programm is pure (at least in the absence of sins such as "unsafePerformIO"). All functions that you write in Haskell are pure.
Side-effects are introduced through monads. They can be used to introduce a sort of "shopping-list -- shopper"-separation. Essentially your program writes a shopping list (which is just data and can be manipulated in a pure fashion), while the language runtime interprets the shopping list and does the effectful shopping. All your code is pure and friendly to equational reasoning and such, whereas the impure code is provided by the compiler-writers.