tags:

views:

112

answers:

4

As i understand Haskell does not have a global state, so is there any way to write a function f that will return f(n - 1) + 1, where n is a number of function call and f(1) = 0.

It should not accept any arguments and used like func f

Prelude> f () 
0
Prelude> f ()
1
+1  A: 

Try something like this:

f 1 = 0
f n = f (n-1) + 1

EDIT: It seems I misunderstood your question; no, you cannot do something like that in haskell; functions ought to be pure. The function in your example is not pure

Gabi Purcaru
Typo: you have `f (n-1) - 1`, they want `f (n-1) + 1`.
Antal S-Z
@Antal S-Z you are fast! I saw it right after I posted it, but it appears you saw it too :)
Gabi Purcaru
+5  A: 

Without using tricks like unsafePerform, it is not possible to define a function that can be called like you showed in your example. However it is possible to define an IO action that does what you want and could be used like this:

Prelude> x <- f 
Prelude> x
0
Prelude> x <- f
Prelude> x
1

Here's an example program that does what you want using IORefs:

import Data.IORef

main = do counter <- newIORef 0
          let f = do count <- readIORef counter
                     modifyIORef counter (+ 1)
                     return count          
          x <- f
          print x
          x <- f
          print x
sepp2k
How can I write such IO action?
Azibo
@Azibo: Just edited to add that information.
sepp2k
A small aside: using `unsafePerformIO` makes it possible to *define* a pure function that looks like it will do what you want, but don't try it. It almost certainly won't work correctly.
John
+4  A: 

You're asking for a way to update some (possibly hidden) state on each call to a procedure, such that the function returns different results given the same input.

Clearly, that's no a referentially transparent function, so we must add something to Haskell's pure-by-default mode. We add notions of computation via monads. You just have to pick the monadic environment you need.

The state monad

The most precise way is to add just exactly the notion of state to your program, via the State monad (not to be confused with the "ST" monad):

import Control.Monad.State.Strict 

-- a (stateful) procedure, that returns and increments an internal state counter 
f :: State Int Int 
f = do 
    n <- get 
    put (n+1) 
    return n 

-- Call 'f' a bunch of times, print the final state. 
main = print $ execState code 0 
 where 
    code = do f; f; f; f

Now 'f' has an internal state component.

Similarly, richer environments, such as IO, allow for State, so you could use the IO monad (or some other state-subsuming computational environment).

Don Stewart
+3  A: 

If you prefer something you can just type from the ghci command line then:

Prelude> :m + Data.IORef
Prelude Data.IORef> n <- newIORef 0
Prelude Data.IORef> let f = do { v <- readIORef n ; writeIORef n (v+1); return v}
Prelude Data.IORef> f
0
Prelude Data.IORef> f
1
Prelude Data.IORef> f
2
Prelude Data.IORef> f
3

Your example wanted to call "f ()", but that is a C-ism that Haskell does not have. If you really want that then just change the definition of "f" to start

let f _ = do {...

"()" is defined in Haskell as the unit value, which is the only value of the unit type "()". You can call "f" with any argument you want; it will be ignored.

Paul Johnson