Nickolay Kolev
Nickolay Kolev

Reputation: 1189

Generating sequential members of an infinite list

I have an infinite list of entities generated thus:

entities =
  let f x = x ++ "'" 
  in "x" : "y" : "z" : map f entities

I would like to define a function which returns a new entity on each invokation. Like this:

> nextEntity
x
> nextEntity
y
.
.
.

I suppose this is the place for the State monad, but will be grateful for pointers.

Some background: if you try to represent natural language sentences in FOL, you need named variables for your entities. "John loves Mary" needs two variables (one for John and one for Mary), "John gives Mary a book" needs three variables (John, Mary, the book), etc. What I need here is a method of generating a new variable name for each "thing" I encounter while processing sentences.

So the function I want to use must keep track of which have already been generated and upon invokation return the next one.

Upvotes: 2

Views: 337

Answers (3)

HaskellElephant
HaskellElephant

Reputation: 9891

Yes, the state Monad is what you want. Nextentities can be written like this:

nextEntity :: State [a] a
nextEntity = modify tail >> gets head

And we can write a function that gives you the first 100 elements like this:

test = sequence (replicate 100 nextEntity)

Print them like this:

main = sequence_ . map print . evalState test $ entities

Upvotes: 1

Dario
Dario

Reputation: 49208

I would like to define a function which returns a new entity on each invokation. Like this:

As Haskell is a purely functional programming language, this is by definition impossible. Any Haskell function will return the same value for the same parameters. A function without parameters thus is constant.

I suppose this is the place for the State monad,

Yes, indeed it is. The state monad represents a computation with some hidden state you can alter. Using a do construct, you can combine stateful computations to bigger ones which share the common state. In particular, every computation just passes the new state to the consecutive ones.

The usage though is quite straightforward.

nextEntity :: State [a] a
nextEntity = do 
  entity:rest <- get
  put rest
  return entity

test = do
   e1 <- nextEntity
   e2 <- nextEntity
   e3 <- nextEntity
   return [e1, e2, e3]

res = fst $ runState test entities

Upvotes: 5

edon
edon

Reputation: 722

For a function to do that, it must have some kind of state, which it changes when it is called, which you can't do with pure Haskell functions. You can use the State monad, but I think there are better ways of solving your problem whatever it might be.

Here's how one might do it inside the State monad

nextEntity :: State Int String
nextEntity = do
               s <- get
               put (s+1)
               return (entities !! s)

Which than you can use it in a calculation inside the State monad like this:

someCalculation = do
                    s1 <- nextEntity
                    s2 <- nextEntity
                    (do something with them)

so different values would get binded to s1 and s2. But all this should be only considered as an exercise on the state monad, because I'm sure there is a better solution to what you are trying to do.

Upvotes: 4

Related Questions