I have translated the following F# code to C# and would appreciate constructive criticism. This code computes the symbolic derivative of the expression f(x)=x³-x-1:
type Expr =
| Int of int
| Var of string
| Add of Expr * Expr
| Mul of Expr * Expr
let rec d f x =
match f with
| Var y when x=y -> Int 1
| Int _ | Var _ -> Int 0
| Add(f, g) -> Add(d f x, d g x)
| Mul(f, g) -> Add(Mul(f, d g x), Mul(g, d f x))
let f =
let x = Var "x"
Add(Add(Mul(x, Mul(x, x)), Mul(Int -1, x)), Int -1)
d f "x"
My translation from F# to C# fragments the d
function into member functions in classes that implement an Expr
interface and adds a hand-written structural pretty printers:
using System;
public interface Expr
{
Expr d(string x);
}
public class Int : Expr
{
int n;
public Int(int m)
{
n = m;
}
public int Value
{
get { return n; }
}
public Expr d(string x)
{
return new Int(0);
}
public override string ToString()
{
return "Int " + n.ToString();
}
}
public class Var : Expr
{
string x;
public Var(string y)
{
x = y;
}
public string Value
{
get { return x; }
}
public Expr d(string y)
{
return (x == y ? new Int(1) : new Int(0));
}
public override string ToString()
{
return "Var \"" + x + "\"";
}
}
public class Add : Expr
{
Expr f, g;
public Add(Expr a, Expr b)
{
f = a;
g = b;
}
public Tuple<Expr, Expr> Value
{
get { return Tuple.Create(f, g); }
}
public Expr d(string y)
{
return new Add(f.d(y), g.d(y));
}
public override string ToString()
{
return "Add(" + f.ToString() + ", " + g.ToString() + ")";
}
}
class Mul : Expr
{
Expr f, g;
public Mul(Expr a, Expr b)
{
f = a;
g = b;
}
public Tuple<Expr, Expr> Value
{
get { return Tuple.Create(f, g); }
}
public Expr d(string y)
{
return new Add(new Mul(f, g.d(y)), new Mul(g, f.d(y)));
}
public override string ToString()
{
return "Mul(" + f.ToString() + ", " + g.ToString() + ")";
}
}
class SymbolicDerivative
{
static void Main(string[] args)
{
var x = new Var("x");
var f = new Add(new Add(new Mul(x, new Mul(x, x)),
new Mul(new Int(-1), x)),
new Int(-1));
Console.WriteLine("{0}", f.d("x").ToString());
}
}
I have also written the derivative function externally to the class hierarchy using the is
operator to inspect the type of a given value but I chose this code because I believe it is more idiomatic OOP style.