简体   繁体   中英

Updating an outer variable in Haskell

There is a sense in which Haskell is a purely functional language, and certainly, idiomatic code tries to be as functional as reasonably possible. At the same time, Haskell does provide support for fairly direct translation of some imperative patterns familiar from other languages, eg http://learnyouahaskell.com/a-fistful-of-monads#do-notation

(I'm aware that there is a sense in which do-notation is 'really' still functional; the point here is that it allows a fairly direct translation of some imperative design patterns.)

One pattern I'm interested in, is one where a function needs to update an outer variable, ie a variable that exists in an outer scope shared with other code. This can be demonstrated simply in Python:

def three():
    n = 0

    def inc():
        nonlocal n
        n += 1

    inc()
    inc()
    inc()
    return n

Is it possible, perhaps with some variant of do-notation, or otherwise, to implement the above design pattern in Haskell? If so, how?

To be clear on the scope of this question:

I'm not asking what's the best way to solve the above problem in Haskell. Obviously, the answer to that would be three = 3 . It's just an example.

I'm not asking whether the above design pattern is good or bad. Obviously, that would be a matter of opinion.

I'm not asking how hard one should try, when writing Haskell, to avoid using imperative design patterns. Obviously, that too would be a matter of opinion.

I'm just asking whether the above design pattern can be implemented in Haskell, and if so, how.

In Haskell, all you have to do is to create the mutable variable (actually, a reference to that) in the outer scope and use it in the inner scope.

Here I used the ST s monad to illustrate the principle, but you can do the same with IO and many other kinds of references.

import Control.Monad.ST
import Data.STRef

three :: ST s Int
three = do
   n <- newSTRef 0
   let inc = modifySTRef' n (+1)
   inc
   inc
   inc
   readSTRef n

main :: IO ()
main = print (runST three)   -- output: 3

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM