Monday, March 21, 2011

Monad(Kleisli triple) in C#

Monad is very powerful tool for combining functions.

The definition of Monad(Kleisli triple) is following:

C : category
T : C → C : endofunctor
A, B : objects of category C
f : morphism of category C

u : A → TA
and
for any morphism f : A → TB, a morphism f' : TA → TB exists and satisfies:
1. u' = id
2. f = f'* u
3. f : A → TB, g : B → TC, (g' * f)' = g' * f'

I show the example of the validation for given value by C# code.

I prepare the following struct:

public struct Param<A>
{
private A value;

public A Value
{
get
{
if (!IsValid)
throws new Exception();

return this.value;
}
set { this.value = value; }
}

public bool IsValid { get; set; }
}

See Param as endfunctor T.
u : A → TA is defined as Unit : A → Param<A> :

Param<A> Unit(Param<A> a)
{
return new Param<A>() { Value = a, IsValid = true, };
}

f : A → TB i.e. Param<B> Validate(B b) { ... }

A function Validate2 : Param<A> → Param<B> , which is (Validate)' :

Param<B> Validate2(Param<A> pa)
{
return (pa.IsValid
? Validate(pa.Value)
: new Param<B>() { Value = default(B), IsValid = false, });
}

If we define the following function Extend, we obtain Validate2 as Extend(Validate).

Func<Param<A>, Param<B>> Extend(Func<A, Param<B>> f)
{
return (pa => (pa.IsValid
? f(pa.Value)
: new Param<B>() { Value = default(B), IsValid = false, }));
}

I confirm Extend(Unit),

Extend(Unit)(pa) =
return (pa => (pa.IsValid
? new Param<A>() { Value = pa.Value, IsValid = true, }
: new Param<A>() { Value = default(A), IsValid = false, }));

This result pa2 = Extend(Unit)(pa) satisfies :
if pa.IsValid then pa2.IsValid and pa2.Value == pa.Value,
if not pa.IsValid then not pa2.IsValid and pa2.Value throws Exception.

i.e. Extend(Unit) is Id.

For ValidateX : A → TB and ValidateY : B → TC,
Extend(Extend(ValidateY)(ValidateX)) =
return (pa => ((Extend(ValidateY)(ValidateX))(pa)).IsValid
? (Extend(ValidateY)(ValidateX))(pa)
: new Param<C>() { Value = default(C), IsValid = false, }));
=
return (pa => ((Extend(ValidateY)(Extend(ValidateX)(pa))).IsValid
? (Extend(ValidateY)(Extend(ValidateX)(pa))
: new Param<C>() { Value = default(C), IsValid = false, }));
=
Extend(ValidateY)(Extend(ValidateX))

These are equal.

No comments:

Post a Comment