patterncsharpMinor
C# state monad implementation
Viewed 0 times
implementationstatemonad
Problem
I want to know whether this thing I wrote in C# is a correct implementation of the state monad.
I've used it in code and it does what I expect it to do, but I'm still not quite sure if I'm doing this right, or if I just pulled something out of my ear and called it a state monad.
I would have made an
Anyway, here's the code:
EDIT: You're not supposed to use mutable structs. Here in particular it's helpful to adhere to that, because the state object in the state monad isn't supposed to be mutable either. Ironically, I had to change StateData from a struct to a class to get the compiler to quit complaining about the constructor. Nonetheless, it is now immutable.
Also, I changed the Lift function so that it no longer passes through stale TResults.
Based on the type signatures and how quaint the code has become, I'm pretty sure this thing is indeed a state monad.
```
// State a
class
I've used it in code and it does what I expect it to do, but I'm still not quite sure if I'm doing this right, or if I just pulled something out of my ear and called it a state monad.
I would have made an
IMonad interface and used that to help test this, but that's not possible.Anyway, here's the code:
// State a
class State
{
// State a t
public struct StateData
{
public TResult result;
public TState state;
}
// return :: t -> m t
public static StateData Return(TState state)
{
StateData monadicValue = new StateData();
monadicValue.result = default(TResult);
monadicValue.state = state;
return monadicValue;
}
// (>>=) :: m t -> (t -> m u) -> m u
public static StateData Bind(StateData monadicValue, Func> func)
{
StateData newMonadicValue = func(monadicValue.state);
return newMonadicValue;
}
// liftM :: (t -> u) -> m t -> m u
// liftM :: m t -> (t -> u) -> m u -- looks more similar to bind this way
public static StateData Lift(StateData monadicValue, Func func)
{
StateData newMonadicValue = new StateData();
newMonadicValue.result = monadicValue.result;
newMonadicValue.state = func(monadicValue.state);
return newMonadicValue;
}
}EDIT: You're not supposed to use mutable structs. Here in particular it's helpful to adhere to that, because the state object in the state monad isn't supposed to be mutable either. Ironically, I had to change StateData from a struct to a class to get the compiler to quit complaining about the constructor. Nonetheless, it is now immutable.
Also, I changed the Lift function so that it no longer passes through stale TResults.
Based on the type signatures and how quaint the code has become, I'm pretty sure this thing is indeed a state monad.
```
// State a
class
Solution
Mutable
structs in C#/.NET are evil for many reasons you can Google. Rewrite as such:internal class State
{
// State a t
public struct StateData
{
public StateData(TResult result, TState state)
{
this.Result = result;
this.State = state;
}
public TResult Result { get; }
public TState State { get; }
}
// return :: t -> m t
public static StateData Return(TState state) => new StateData(default(TResult), state);
// (>>=) :: m t -> (t -> m u) -> m u
public static StateData Bind(
StateData monadicValue,
Func> func) => func(monadicValue.State);
// liftM :: (t -> u) -> m t -> m u
// liftM :: m t -> (t -> u) -> m u -- looks more similar to bind this way
public static StateData Lift(
StateData monadicValue,
Func func) => new StateData(monadicValue.Result, func(monadicValue.State));
}Code Snippets
internal class State<TResult>
{
// State a t
public struct StateData<TState>
{
public StateData(TResult result, TState state)
{
this.Result = result;
this.State = state;
}
public TResult Result { get; }
public TState State { get; }
}
// return :: t -> m t
public static StateData<TState> Return<TState>(TState state) => new StateData<TState>(default(TResult), state);
// (>>=) :: m t -> (t -> m u) -> m u
public static StateData<TNewState> Bind<TState, TNewState>(
StateData<TState> monadicValue,
Func<TState, StateData<TNewState>> func) => func(monadicValue.State);
// liftM :: (t -> u) -> m t -> m u
// liftM :: m t -> (t -> u) -> m u -- looks more similar to bind this way
public static StateData<TNewState> Lift<TState, TNewState>(
StateData<TState> monadicValue,
Func<TState, TNewState> func) => new StateData<TNewState>(monadicValue.Result, func(monadicValue.State));
}Context
StackExchange Code Review Q#23559, answer score: 2
Revisions (0)
No revisions yet.