Natural number sequence generator
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开发者_如何学Python any arguments and used like func f
Prelude> f ()
0
Prelude> f ()
1
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
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).
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.
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
精彩评论