Last active
March 17, 2017 01:09
-
-
Save dogwith1eye/b0d76285324e065de934c94e9b838aab to your computer and use it in GitHub Desktop.
Visitor Pattern Rank 2 Types
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
namespace HigherRankC | |
{ | |
abstract class TypeWrapper<T> | |
{ | |
public TypeWrapper(T value) | |
{ | |
this.Value = value; | |
} | |
public T Value { get; } | |
public abstract U Accept<U>(IVisitor<T, U> visitor); | |
} | |
interface IVisitor<T, U> | |
{ | |
U Visit(T t); | |
} | |
interface IShowable<T> | |
{ | |
T Value { get; } | |
U Accept<U>(IVisitor<T, U> visitor); | |
} | |
class StringWrapper : TypeWrapper<string>, IShowable<string> | |
{ | |
public StringWrapper(string value) : base(value) { } | |
public interface IStringVisitor<U> : IVisitor<string, U> { } | |
public U Accept<U>(IStringVisitor<U> visitor) | |
{ | |
return visitor.Visit(this.Value); | |
} | |
public override U Accept<U>(IVisitor<string, U> visitor) | |
{ | |
return visitor.Visit(this.Value); | |
} | |
} | |
class IntWrapper : TypeWrapper<int>, IShowable<int>, IRoundable<int> | |
{ | |
public IntWrapper(int value) : base(value) { } | |
public interface IIntVisitor<U> : IVisitor<int, U> { } | |
public U Accept<U>(IIntVisitor<U> visitor) | |
{ | |
return visitor.Visit(this.Value); | |
} | |
public override U Accept<U>(IVisitor<int, U> visitor) | |
{ | |
return visitor.Visit(this.Value); | |
} | |
} | |
class FloatWrapper : TypeWrapper<float>, IShowable<float>, IRoundable<float> | |
{ | |
public FloatWrapper(float value) : base(value) { } | |
public interface IFloatVisitor<U> : IVisitor<float, U> { } | |
public U Accept<U>(IFloatVisitor<U> visitor) | |
{ | |
return visitor.Visit(this.Value); | |
} | |
public override U Accept<U>(IVisitor<float, U> visitor) | |
{ | |
return visitor.Visit(this.Value); | |
} | |
} | |
class ShowVisitor : StringWrapper.IStringVisitor<string>, | |
IVisitor<string, string>, | |
IntWrapper.IIntVisitor<string>, | |
IVisitor<int, string>, | |
FloatWrapper.IFloatVisitor<string> | |
{ | |
public string Visit(string t) | |
{ | |
return t; | |
} | |
public string Visit(int t) | |
{ | |
return t.ToString(); | |
} | |
public string Visit(float t) | |
{ | |
return t.ToString(); | |
} | |
public string Show<T>(IShowable<T> showable) | |
{ | |
return showable.Accept(this as IVisitor<T, string>); | |
} | |
} | |
interface IRoundable<T> | |
{ | |
T Value { get; } | |
U Accept<U>(IVisitor<T, U> visitor); | |
} | |
class RoundVisitor : IntWrapper.IIntVisitor<int>, | |
IVisitor<int, int>, | |
FloatWrapper.IFloatVisitor<int>, | |
IVisitor<float, int> | |
{ | |
public int Visit(int t) | |
{ | |
return t; | |
} | |
public int Visit(float f) | |
{ | |
return (int)Math.Round(f); | |
} | |
public int Round<T>(IRoundable<T> roundable) | |
{ | |
return roundable.Accept(this as IVisitor<T, int>); | |
} | |
} | |
static class Prelude | |
{ | |
// show :: forall a. (IShowable a) => a -> string | |
public static string Show<T>(IShowable<T> t) | |
{ | |
var show = new ShowVisitor(); | |
return t.Accept(show as IVisitor<T, string>); | |
} | |
// show :: forall a. (IRoundable a) => a -> int | |
public static int Round<T>(IRoundable<T> t) | |
{ | |
var round = new RoundVisitor(); | |
return t.Accept(round as IVisitor<T, int>); | |
} | |
// accept :: forall b. (forall a. (IIntVisitor a) => a) -> b | |
public static U Accept<U>(IntWrapper.IIntVisitor<U> v) | |
{ | |
var i = new IntWrapper(1); | |
return i.Accept(v); | |
} | |
} | |
class Program | |
{ | |
static void Main(string[] args) | |
{ | |
var s = new StringWrapper("foo"); | |
var i = new IntWrapper(1); | |
var f = new FloatWrapper(5.5f); | |
var show = new ShowVisitor(); | |
var round = new RoundVisitor(); | |
// accept :: forall b. (forall a. IStringVisitor a => a) -> b | |
var r1 = s.Accept(show); | |
//var r4 = s.Accept(round); | |
var r11 = show.Show(s); | |
var r111 = Prelude.Show(s); | |
//var r44 = round.Round(s); | |
//var r444 = Prelude.Round(s); | |
// accept :: forall b. (forall a. IIntVisitor a => a) -> b | |
var r2 = i.Accept(show); | |
var r5 = i.Accept(round); | |
var r22 = show.Show(i); | |
var r222 = Prelude.Show(i); | |
var r55 = round.Round(i); | |
var r555 = Prelude.Round(i); | |
// accept :: forall b. (forall a. IFloatVisitor a => a) -> b | |
var r3 = f.Accept(show); | |
var r6 = f.Accept(round); | |
var r33 = show.Show(f); | |
var r333 = Prelude.Show(f); | |
var r66 = round.Round(f); | |
var r666 = Prelude.Round(f); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment