Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>HigherLogics is my blog, and I've spent a lot of time investigating this question. The limitation is indeed abstraction over type constructors, aka "generics over generics". It seems the best you can do to mimic ML modules and functors requires at least one (semi-safe) cast.</p> <p>It basically comes down to defining an abstract type, and an interface which corresponds to the module signature that operates on that type. The abstract type and the interface share a type parameter B which I term a "brand"; the brand is generally just the subtype that implements the module interface. The brand ensures that the type passed in is the proper subtype expected by the module.</p> <pre><code>// signature abstract class Exp&lt;T, B&gt; where B : ISymantics&lt;B&gt; { } interface ISymantics&lt;B&gt; where B : ISymantics&lt;B&gt; { Exp&lt;int, B&gt; Int(int i); Exp&lt;int, B&gt; Add(Exp&lt;int, B&gt; left, Exp&lt;int, B&gt; right); } // implementation sealed class InterpreterExp&lt;T&gt; : Exp&lt;T, Interpreter&gt; { internal T value; } sealed class Interpreter : ISymantics&lt;Interpreter&gt; { Exp&lt;int, Interpreter&gt; Int(int i) { return new InterpreterExp&lt;int&gt; { value = i }; } Exp&lt;int, Interpreter&gt; Add(Exp&lt;int, Interpreter&gt; left, Exp&lt;int, Interpreter&gt; right) { var l = left as InterpreterExp&lt;int&gt;; //semi-safe cast var r = right as InterpreterExp&lt;int&gt;;//semi-safe cast return new InterpreterExp&lt;int&gt; { value = l.value + r.value; }; } } } </code></pre> <p>As you can see, the cast is mostly safe, since the type system ensures the brand of the expression type matches the brand of the interpreter. The only way to screw this up, is if the client creates his own Exp class and specifies the Interpreter brand. There is a safer encoding which avoids this problem too, but it's far too unwieldy for ordinary programming.</p> <p>I later <a href="http://higherlogics.blogspot.com/2009/06/mobile-code-in-c-via-finally-tagless.html" rel="noreferrer">used this encoding and translated the examples</a> from one of Oleg's papers written in MetaOCaml, to use C# and Linq. The interpreter can transparently run programs written using this embedded language server-side in ASP.NET or client-side as JavaScript.</p> <p>This abstraction over interpreters is a feature of Oleg's final tagless encoding. Links to his paper are provided in the blog post.</p> <p>Interfaces are first-class in .NET, and since we use interfaces to encode module signatures, modules and module signatures are also first-class in this encoding. Thus, functors simply use the interface directly in place of module signatures, ie. they would accept an instance of ISymantics&lt;B&gt; and delegate any calls to it.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload