Misconceptions about purely functional languages?

I often encounter the following statements / arguments:

  1. Pure functional programming languages do not allow side effects (and are therefore of little use in practice because any useful program does have side effects, e.g. when it interacts with the external world).
  2. Pure functional programming languages do not allow to write a program that maintains state (which makes programming very awkward because in many application you do need state).

I am not an expert in functional languages but here is what I have understood about these topics until now.

Regarding point 1, you can interact with the environment in purely functional languages but you have to explicitly mark the code (functions) that introduces side effects (e.g. in Haskell by means of monadic types). Also, as far as I know computing by side effects (destructively updating data) should also be possible (using monadic types?) even though it is not the preferred way of working.

Regarding point 2, as far as I know you can represent state by threading values through several computation steps (in Haskell, again, using monadic types) but I have no practical experience doing this and my understanding is rather vague.

So, are the two statements above correct in any sense or are they just misconceptions about purely functional languages? If they are misconceptions, how did they come about?
Could you write a (possibly small) code snippet illustrating the Haskell idiomatic way to (1) implement side effects and (2) implement a computation with state?

3

For the purposes of this answer I define “purely functional language” to mean a functional language in which functions are referentially transparent, i.e. calling the same function multiple times with the same arguments will always produce the same results. This is, I believe, the usual definition of a purely functional language.

Pure functional programming languages do not allow side effects (and are therefore of little use in practice because any useful program does have side effects, e.g. when it interacts with the external world).

The easiest way to achieve referential transparency would indeed be to disallow side effects and there are indeed languages in which that is the case (mostly domain specific ones). However it is certainly not the only way and most general purpose purely functional languages (Haskell, Clean, …) do allow side effect.

Also saying that a programming language without side effects is little use in practice isn’t really fair I think – certainly not for domain specific languages, but even for general purpose languages, I’d imagine a language can be quite useful without providing side effects. Maybe not for console applications, but I think GUI applications can be nicely implemented without side-effects in, say, the functional reactive paradigm.

Regarding point 1, you can interact with the environment in purely functional languages but you have to explicitly mark the code (functions) that introduces them (e.g. in Haskell by means of monadic types).

That’s a bit over simplifying it. Just having a system where side-effecting functions need to be marked as such (similar to const-correctness in C++, but with general side-effects) is not enough to ensure referential transparency. You need to ensure that a program can never call a function multiple times with the same arguments and get different results. You could either do that by making things like readLine be something that’s not a function (that’s what Haskell does with the IO monad) or you could make it impossible to call side-effecting functions multiple times with the same argument (that’s what Clean does). In the latter case the compiler would ensure that every time you call a side-effecting function, you do so with a fresh argument, and it would reject any program where you pass the same argument to a side-effecting function twice.

Pure functional programming languages do not allow to write a program that maintains state (which makes programming very awkward because in many application you do need state).

Again, a purely functional language might very well disallow mutable state, but it’s certainly possible to be pure and still have mutable state, if you implement it in the same way as I described with side-effects above. Really mutable state is just another form of side-effects.

That said, functional programming languages definitely do discourage mutable state – pure ones especially so. And I don’t think that that makes programming awkward – quite the opposite. Sometimes (but not all that often) mutable state can’t be avoided without losing performance or clarity (which is why languages like Haskell do have facilities for mutable state), but most often it can.

If they are misconceptions, how did they come about?

I think many people simply read “a function must produce the same result when called with the same arguments” and conclude from that that it’s not possible to implement something like readLine or code that maintains mutable state. So they’re simply not aware of the “cheats” that purely functional languages can use to introduce these things without breaking referential transparency.

Also mutable state is heavily discourages in functional languages, so it isn’t all that much of a leap to assume it’s not allowed at all in purely functional ones.

Could you write a (possibly small) code snippet illustrating the Haskell idiomatic way to (1) implement side effects and (2) implement a computation with state?

Here’s an application in Pseudo-Haskell that asks the user for a name and greets him. Pseudo-Haskell is a language that I just invented, which has Haskell’s IO system, but uses more conventional syntax, more descriptive function names and has no do-notation (as that would just distract from how exactly the IO monad works):

greet(name) = print("Hello, " ++ name ++ "!")
main = composeMonad(readLine, greet)

The clue here is that readLine is a value of type IO<String> and composeMonad is a function that takes an argument of type IO<T> (for some type T) and another argument that is a function which takes an argument of type T and returns a value of type IO<U> (for some type U). print is a function that takes a string and returns a value of type IO<void>.

A value of type IO<A> is a value that “encodes” a given action that produces a value of type A. composeMonad(m, f) produces a new IO value that encodes the action of m followed by the action of f(x), where x is the value produces by performing the action of m.

Mutable state would look like this:

counter = mutableVariable(0)
increaseCounter(cnt) =
    setIncreasedValue(oldValue) = setValue(cnt, oldValue + 1)
    composeMonad(getValue(cnt), setIncreasedValue)

printCounter(cnt) = composeMonad( getValue(cnt), print )

main = composeVoidMonad( increaseCounter(counter), printCounter(counter) )

Here mutableVariable is a function that takes value of any type T and produces a MutableVariable<T>. The function getValue takes MutableVariable and returns an IO<T> that produces its current value. setValue takes a MutableVariable<T> and a T and returns an IO<void> that sets the value. composeVoidMonad is the same as composeMonad except that the first argument is an IO that does not produce a sensible value and the second argument is another monad, not a function that returns a monad.

In Haskell there’s some syntactic sugar, that makes this whole ordeal less painful, but it’s still obvious that mutable state is something that language doesn’t really want you to do.

4

IMHO you are confused because there is a difference between a pure language and a pure function. Let us begin with the function. A function is pure if it will (given the same input) always return the same value and does not cause any observable side effects. Typical examples are mathematical functions like f(x) = x * x. Now consider an implementation of this function. It would be pure in most languages even those which are not generally considered pure functional languages e.g. ML. Even a Java or C++ method with this behavior can be considered as pure.

So what is a pure language? Strictly speaking one might expect that a pure language does not let you express functions that are not pure. Let us call this the idealistic definition of a pure language. Such a behavior is highly desirable. Why? Well the nice thing about a program consisting of only pure functions is that you can replace the function application with its value without changing the meaning of the program. This makes very easy to reason about programs because once you know the result you can forget the way it was computed. Purity might also allows the compiler to perform certain aggressive optimizations.

So what if you need some internal state? You can mimic state in a pure language simply by adding the state before the computation as an input parameter and the state after the computation as part of the result. Instead of Int -> Bool you get something like Int -> State -> (Bool, State). You simply make the dependency explicit (which is considered good practice in any programming paradigm). BTW there is a monad that is a particularly elegant way to combine such state-mimicking functions into bigger state-mimicking functions. This way you definitely can “maintain state” in a pure language. But you have to make it explicit.

So does this mean I can interact with the outside? After all a useful program must interact with the real world in order to be useful. But input and output are obviously not pure. Writing a specific byte to a specific file might be fine for the first time. But executing the exact same operation a second time might return an error because the disk is full. Clearly there exists no pure language (in the idealistic meaning) that can write to a file.

So we are faced with a dilemma. We want mostly pure functions but some side effects are absolutely required and those are not pure. Now a realistic definition of a pure language would be that there has to be some means to separate the pure parts from the other parts. The mechanism must ensure that no impure operation sneaks its way into the pure parts.

In Haskell this is done with the IO type. You cannot destruct an IO result (without unsafe mechanisms). Thus you can only process IO results with functions that are defined in the IO module themselves. Luckily there is a very flexible combinators which allows you to take an IO result and process it in a function as long as that function returns another IO result. This combinator is called bind (or >>=) and has the type IO a -> (a -> IO b) -> IO b. If you generalize this concept you arrive at the monad class and IO happens to be an instance of it.

18

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật