(basically i'm trying to understand various ways to deal with
statefulness; i've been looking at ioRef, and am now trying to learn
about the State monad, and wonder what other options there might be.)
thanks.
Explicit passing is, of course, a useful thing, if you want to be that
verbose. Personally I consider it rather annoying, though, so I prefer
using State monads.
Another option is to make use of concurrency, but that works only in the
IO monad, and it should be used carefully, not to be too imperative.
One example of this: When I write a server program that maintains an
online database of objects, I generally do this in a separate thread,
which can be queried using a Chan.
Greets,
Ertugrul.
--
nightmare = unsafePerformIO (getWrongWife >>= sex)
Yes, if the state has managable size. Functions like "iterate" are
quite useful for that. If the state gets to big, the State monad
is better to "hide the plumbing" (after all, it's just a formalized
way to thread state around from pure functions to "themselves").
Of course, in Erlang you can distribute state among various process,
turning each process into an "object", so Erlang has a natural way to
split up state into small chunks (which is what OOP is about in the
first place, at least IMHO). Haskell can't do that easily, or at least
I haven't seen an idiom which would make that approach look natural.
> (basically i'm trying to understand various ways to deal with
> statefulness; i've been looking at ioRef, and am now trying to learn
> about the State monad, and wonder what other options there might be.)
I think these three are the main options. If state is simple, pass it
around. If it gets complex, hide it in a State monad or a derivate.
If you're doing IO anyway, use IORefs.
- Dirk
> Of course, in Erlang you can distribute state among various process,
> turning each process into an "object", so Erlang has a natural way to
> split up state into small chunks (which is what OOP is about in the
> first place, at least IMHO). Haskell can't do that easily, or at least
> I haven't seen an idiom which would make that approach look natural.
Isn't this a good use case for StateT over IO?
mainThread :: StateT AppState IO ()
mainThread = do
doSomething1
s <- get
liftIO $ forkIO $ evalStateT subThread (partOf s)
doSomething2
subThread :: StateT PartOfAppState IO ()
subThread = doSomething3
Maybe I'm misunderstanding you.
>> Of course, in Erlang you can distribute state among various process,
>> turning each process into an "object", so Erlang has a natural way to
>> split up state into small chunks (which is what OOP is about in the
>> first place, at least IMHO). Haskell can't do that easily, or at least
>> I haven't seen an idiom which would make that approach look natural.
> Isn't this a good use case for StateT over IO?
Why should it?
> mainThread :: StateT AppState IO ()
> mainThread = do
> doSomething1
> s <- get
> liftIO $ forkIO $ evalStateT subThread (partOf s)
> doSomething2
>
> subThread :: StateT PartOfAppState IO ()
> subThread = doSomething3
> Maybe I'm misunderstanding you.
At least I don't understand what you're aiming at :-) Of course
one can imitate Erlang processes, but in Erlang that is natural and
the VM is optimized for it. In Haskell, that isn't the case.
- Dirk
> Ertugrul Söylemez <e...@ertes.de> wrote:
> > Dirk Thierbach <dthie...@usenet.arcornews.de> wrote:
> >
> >> Of course, in Erlang you can distribute state among various
> >> process, turning each process into an "object", so Erlang has a
> >> natural way to split up state into small chunks (which is what OOP
> >> is about in the first place, at least IMHO). Haskell can't do that
> >> easily, or at least I haven't seen an idiom which would make that
> >> approach look natural.
> >
> > Isn't this a good use case for StateT over IO?
>
> Why should it?
>
> > [...]
> >
> > Maybe I'm misunderstanding you.
>
> At least I don't understand what you're aiming at :-) Of course one
> can imitate Erlang processes, but in Erlang that is natural and the VM
> is optimized for it. In Haskell, that isn't the case.
Likely I'm misunderstanding you. =) It seems an Erlang process is
something different from a Haskell thread. I don't know Erlang too
well.
On the other hand, many features and concepts that are primitive in
other languages (i.e. language or RTS features) are library
functionalities in Haskell, so in fact you could say about almost
everything that it's just an imitation of what is a primitive feature in
another language. This is even true for the most basic concepts like
state, pointers, control structures, etc.
Considering this, I don't see any problems with imitating concepts from
other languages, as long as the imitation is solid and beautiful. In
Haskell, this is usually the case.
Yes. Most programming languages are Turing complete, so all those
languages can emulate each other.
> Considering this, I don't see any problems with imitating concepts from
> other languages, as long as the imitation is solid and beautiful. In
> Haskell, this is usually the case.
The key word is *natural*. In Erlang, it's natural to have lots of
little processes that represent a very fine grained partitioning of
the whole state. One can imitate that in Haskell, but (at least to me)
it wouldn't feel natural -- I'd rather use a low number of threads
that in turn partition their state in the ways mentioned before.
So while there's indeed no problem simulating either approach in the
other language, it's just not something I would do. And there may be
performance penalties (because the Erlang VM is heavily optimized for
*lots* of distributed processes), as well.
- Dirk
> Ertugrul Söylemez <e...@ertes.de> wrote:
>
> > Considering this, I don't see any problems with imitating concepts
> > from other languages, as long as the imitation is solid and
> > beautiful. In Haskell, this is usually the case.
>
> The key word is *natural*. In Erlang, it's natural to have lots of
> little processes that represent a very fine grained partitioning of
> the whole state. One can imitate that in Haskell, but (at least to me)
> it wouldn't feel natural -- I'd rather use a low number of threads
> that in turn partition their state in the ways mentioned before.
I think, this is just your personal view, maybe because you have learned
Haskell another way or with another background than I have. I use
concurrency very heavily, even for very simple things like managing an
object database:
data DBCommand = Add Key Object |
Delete Key |
GetObject k (Maybe v -> IO ())
DoSomething
database :: Chan DBCommand -> StateT (Map Key Object) IO ()
database cmdChan =
forever $ do
cmd <- liftIO (readChan cmdChan)
case cmd of
Add k v -> modify $ Map.insert k v
Delete k -> modify $ Map.delete k
GetObject k f -> get >>= liftIO . f . Map.lookup k
DoSomething -> ...
I view this as a distinct, independent mini-program that receives orders
from other programs and has its own, independent state. Sometimes I use
concurrency even for the most basic and trivial things:
idGenerator <- newEmptyMVar
forkIO $ forM_ [1..] (putMVar idGenerator)
> So while there's indeed no problem simulating either approach in the
> other language, it's just not something I would do. And there may be
> performance penalties (because the Erlang VM is heavily optimized for
> *lots* of distributed processes), as well.
This may be because you're thinking that imitations are unnatural.
Haskell's concurrency imitates Erlang's in many places, but it's very
natural, performs very well (up to outperforming Erlang) and it's very
convenient. It's natural in Haskell, too, to give each client an own
thread, or even multiple threads, each with their own state, which can
communicate with each other. Probably even more natural than in Erlang,
because I don't even notice that usually the next thing I do after
'accept' is 'forkIO'.
> Another option is to make use of concurrency, but that works only in the
> IO monad, and it should be used carefully, not to be too imperative.
thanks (to you and others) for the help, it really is starting to sink
in to my brain, even if it requires repetition (http://tinyurl.com/
65563q) :-}