I've been trying to implement raw lambda calculus on C# but I am having some troubles implementing it, as in the end, I am always asked for objects.
I would like something that would allow me, for instance, to define a few basic logical combinators, such as
I = Lambda x. x
M = Lambda x. x(x)
but C# seems to run on the assumption that it will get an object in the end. I've tried to define them in various ways, such as
using lambda = Func<Object, Object>;
using lambda = Func<Func<Object, Object>, Func<Object, Object>>;
using lambda = Func<Func, Func>;
and so on, but either those do not obey the syntax or are incompatible with
lambda I = x => x;
lambda M = x => x(x);
I tried using the delegate
public delegate object lambda(Object o);
static object i(object o)
{
return o;
}
static object m(object o)
{
return ((lambda)o)(o);
}
But in the end, any actual use of those functions will still require an argument at the end of the line, and a dummy argument like
m(m(i('')));
will simply lead to a cast error during execution.
Is there a way to implement typeless lambda calculus natively, or do I have to go back to string processing?
For an example of execution of the program, it would look something like this. For the following functions :
lambda i(lambda x)
{
print("i");
return x;
}
lambda m(lambda x)
{
print("m");
return x(x);
}
The execution of (m(m))(i) should be something like m(m) is evaluated, returning m(m) after printing "m", which gives us back the original (m(m))(i), which will then print an infinite amount of "m" (this is the simplest infinite loop with logical combinators, although this will involve some trampolining later on to avoid blowing the stack).
Rather than encoding a lambda expression as Func<,> (which is probably not a good match for untyped lambda calculus), you should encode it as an abstract syntax tree. Something like this:
public class LambdaAbstraction: ILambdaExpression {
public LambdaVariable Variable { get; set; }
public ILambdaExpression Body { get; set; }
}
public class LambdaApplication: ILambdaExpression {
public ILambdaExpression Function { get; set; }
public ILambdaExpression Argument { get; set; }
}
public class LambdaVariable: ILambdaExpression {
public string Name { get; set; }
}
For example, M would be
ILambdaExpression M = new LambdaAbstraction {
Variable = new LambdaVariable { Name = "x" },
Body = new LambdaApplication {
Function = new LambdaVariable { Name = "x" },
Argument = new LambdaVariable { Name = "x" }
}
}
Then it's quite straightforward to implement recursive methods for alpha renaming and beta reductions on this data structure.
Related
I want to get the Expression of the Expression-bodied Property. I have no idea how to do that;/ Here is the simple code snippet:
class TestTest
{
public int A { get; set; } = 5;
public int AX5 => A * 5;
}
public class Program
{
public static void Main()
{
var testObj = new TestTest();
Expression<Func<TestTest, int>> expr = (t) => t.AX5;
}
}
This code works, but AX5 is not marked as Expression, it is the simple Int32 property.
This is the result i want to get from the property:
The so called "Expression-Body" is just sugar to shorten function and property declarations. It does not have anything to do with the Expression<> type.
The 'expression-bodied' property in your class is equivalent to:
public int AX5
{
get { return A * 5; }
}
However, if you really wanted to capture this readonly property, you would have to retrieve the compiler generated get-method via reflection and then add an extra parameter to the Func<int> in order to pass the object-instance the property belongs to -> Func<TestTest, int>.
Here's an example:
class TestTest
{
public int A { get; set; } = 5;
public int AX5 => A * 5;
}
var f = typeof(TestTest).GetMethod("get_AX5")
.CreateDelegate(typeof(Func<TestTest, int>))
as Func<TestTest, int>;
Expression<Func<TestTest, int>> exp = instance => f(instance);
Note this is adding an additional function call to capture the new lambda-expression. Converting the get-method to an expression otherwise would get quite complicated.
This is not very useful though, usually you want to work the other way around and build Expression Trees to compile them to delegates later on.
Checkout the docs for Expression Trees for further information.
I want to make this code shorter, via passing the type as a parameter to targetUnitOfWork.Query.
There are two types SomeListItem and SomeList. And depending on the actual type I have to call either Query<SomeListItem> or Query<SomeList> as it is shown below.
Type typeName = targetClassInfo.ClassType;
if (typeName.Equals(typeof(SomeListItem)))
{
target = targetUnitOfWork
.Query<SomeListITem>()
.Where(i => i.Name.Equals(otherObj.Name)).Where(j => j.SortKey == otherObj.SortKey);
}
else if (typeName.Equals(typeof(SomeList)))
{
target = targetUnitOfWork
.Query<SomeList>()
.Where(i => i.Name.Equals(otherObj.Name)).Where(j => j.SortKey == otherObj.SortKey);
}
else
{
target = targetClassInfo.CreateNewObject(targetUnitOfWork);
}
How can I solve this task?
Preface
We will not cover in this answer the design decision made by the authors of the code. It's only worth to say that this kind of heterogeneous generics should be left to pattern matching mechanism instead of polymorphic one.
Motivation
Either way, there are plenty of cases where you want to dynamically put generic types and invoke methods in the chain. It's mostly done in projects serving libraries and frameworks for later usage, where parameters are inherited from the user input, or they come lately to the project as an extension by the developers.
Reflection
Luckily, .NET Framework (and Core as well, the code bellow is .NET Framework) provides a rich Reflection library where you can do your metaprogramming model.
The Reflection library provides a way to introspect the program, compromising the static typization in favor of dynamic one e.g. to find a method by its name, because it comes from the user input. It's not its sole purpose, but we will use it this way.
Action in code
In our scenario, we need to call the Query<T> method with arbitrary <T> which comes from the user input. So let's define a function that will serve this functionality. We will call it Test:
static void Test(Type type, TestGenerics testGenerics, String otherObjectName)
It receives the System.Type, an object in our case TestGenerics and a String to test the name property as in the question.
Our TestGenerics object is a fake class that mimics the question's semantics:
class TestGenerics
{
public IEnumerable<T> Query<T>() where T : new()
{
return Enumerable.Repeat(new T(), 10);
}
}
First of all, we need to find the Query method by name. Since it's the one and only method named this way (no overloads) we can safely use FirstOrDefault:
Object enumerable = testGenerics.GetType().GetMethods().FirstOrDefault(m => m.Name == "Query")
But we cannot invoke it directly, as it accepts not only arguments, but generic parameters as well. We can provide them, by providing Type to MakeGenericMethod(Type) reflection's method:
.MakeGenericMethod(type)
And then we are ready to Invoke it without arguments (as it does not accept any), but we need to specify the object it will be invoked from (in our case testGenerics):
.Invoke(testGenerics, null);
Cool so far, there are the dragons to come here, because we need now to build the i => i.name == otherObjectName lambda. The Where method from IEnumerable<T> extensions (in fact, it's a static method in System.Linq.Enumerable) receives a Func<T, R> instead of Predicate<T>, so we need to build one:
Type predicateType = typeof(Func<,>).MakeGenericType(type, typeof(bool));
This builds Func<,> e.g. a Func type with two generic parameters. The first is the type passed, and the second is boolean to mimic a predicate by function.
Now we need to build the lambdas left side by making a parameter of the given type:
ParameterExpression predParam = Expression.Parameter(type, "i");
And getting the field name from it them:
Expression left = Expression.Field(predParam, type.GetField("name"));
And the right side of the expressions is the name we will compare it with:
Expression right = Expression.Constant(otherObjectName, typeof(string));
Building the whole lambda is the next step. From the predicate type (Func<T, R>, the equality expression and the predicate param "i"):
LambdaExpression lambda = Expression.Lambda(predicateType, Expression.Equal(left, right), predParam);
Now we need to find the Where method. It's in the class containing all the extension methods and not in the IEnumerable interface:
IEnumerable<MethodInfo> methodsEnumerable = typeof(System.Linq.Enumerable)
.GetMethods(BindingFlags.Static | BindingFlags.Public);
MethodInfo where = methodsEnumerable.Where(m => m.GetParameters().Length == 2).FirstOrDefault(m => m.Name == "Where");
But this is a generic method, receiving the type from the input, so we need to do this as well:
MethodInfo genericWhere = where.MakeGenericMethod(type);
Since it is a static method, the object must be passed as an argument (as for the semantics of an extension method). The first argument in the object array is the extension interface (IEnumerable e.g. the return type of Query) and the second argument is the above lambda - compiled:
Object response = genericWhere.Invoke(enumerable, new[] {enumerable, lambda.Compile()});
And here we will stop with the example. You will need to tweak it for your case and add the other method calls. It's very verbose and ugly as well, but will work for any kind of objects containing the name field. In bigger scenarios, if you don't couple to a certain field hardcoded, it will work for wide variety of inputs. The same way how frameworks works with our code.
The full example you can find below:
class TypeOne
{
public string name;
}
class TypeTwo
{
public string name;
}
internal class Program
{
public static void Main(string[] args)
{
Test(typeof(TypeOne), new TestGenerics(), "John");
Test(typeof(TypeTwo), new TestGenerics(), "Smith");
}
static void Test(Type type, TestGenerics testGenerics, String otherObjectName)
{
Object enumerable = testGenerics.GetType().GetMethods().FirstOrDefault(m => m.Name == "Query")
.MakeGenericMethod(type)
.Invoke(testGenerics, null);
Type predicateType = typeof(Func<,>).MakeGenericType(type, typeof(bool));
ParameterExpression predParam = Expression.Parameter(type, "i");
Expression left = Expression.Field(predParam, type.GetField("name"));
Expression right = Expression.Constant(otherObjectName, typeof(string));
LambdaExpression lambda = Expression.Lambda(predicateType, Expression.Equal(left, right), predParam);
IEnumerable<MethodInfo> methodsEnumerable = typeof(System.Linq.Enumerable)
.GetMethods(BindingFlags.Static | BindingFlags.Public);
MethodInfo where = methodsEnumerable.Where(m => m.GetParameters().Length == 2).FirstOrDefault(m => m.Name == "Where");
MethodInfo genericWhere = where.MakeGenericMethod(type);
Object response = genericWhere.Invoke(enumerable, new[] {enumerable, lambda.Compile()});
Console.WriteLine(response);
}
}
class TestGenerics
{
public IEnumerable<T> Query<T>() where T : new()
{
return Enumerable.Repeat(new T(), 10);
}
}
Why don't use generic method like this:
private void SomeMethod<T>()
{
target = targetUnitOfWork
.Query<T>()
.Where(i => i.Name.Equals(otherObj.Name)).Where(j => j.SortKey == otherObj.SortKey);
}
Then you can call SomeMethod<SomeList>() or SomeMethod<SomeListItem>()
This is what you want to do, right?
class Program
{
static void Main(string[] args)
{
List<object> listOfObjects = new List<object>() { new Item(), new Dog(), new Cat(), new Human() };
Dog martin = GetFirstOrDefault<Dog>(listOfObjects);
}
static T GetFirstOrDefault<T>(List<object> listOfObjects)
{
return (T)listOfObjects.Where(x => x.GetType() == typeof(T)).FirstOrDefault();
}
}
class Item
{
public string Name { get; set; }
public string Color { get; set; }
}
class Dog
{
public string Name { get; set; }
public int Age { get; set; }
}
class Cat
{
public string Name { get; set; }
public int Age { get; set; }
}
class Human
{
public string Name { get; set; }
public DateTime Birth { get; set; }
}
Things are only going to get complicated (messy?) from here on.
Ok, so first two queries are same. So, you might go for a generic method. Something of this sort:
public IEnumerable<T> GetListTarget<T>(bool applyWhere) // You will need to add an constraint here that is applicable to both classes. Only then compiler will be able to understand the properties you are using in the where method
{
if (applyWhere)
{
return targetUnitOfWork
.Query<T>()
.Where(i => i.Name.Equals(otherObj.Name)).Where(j => j.SortKey == otherObj.SortKey);
}
else
{
return targetClassInfo.CreateNewObject(targetUnitOfWork);
}
}
In Factory.Process(..) method, I want get hold of instances of MyClass that are being used in the lambda expression of the Func delegate. But, How?
Can someone help me find a way to do it.
Edit: This is an artificial example that demonstates my need. My intention behind this approach is that, I want to keep track of (or subscribe to) all the MyClass objects that are used in the delegate definition. So that, I can recalculate my total value whenever any MyClass object value is changed. Please suggest as to how to go about to solve this.
Note: Expression tree doesnt seem to help in my case because I cant modify my parameter type at this moment and it restricts the usage of my complex function definitions.
public class MyClass
{
public int Value;
public MyClass(int value)
{
Value = value;
}
}
public class TestClass
{
public void TestMethod()
{
var obj1 = new MyClass(10);
var obj2 = new MyClass(20);
Factory.Process(() => obj1.Value + obj2.Value);
}
}
public static class Factory
{
public static void Process(Func<int> function)
{
var total = function.Invoke();
// Here, apart from invoke, I want to access the all the instances of MyClass that are used in 'function'
// but how do I get to obj1 and obj2 objects through the 'function' delegate?
}
}
First of all, if you type an input parameter as just Func<T> it's not an expression, but just a lambda syntax for delegates.
If you want to be able to access the expression and do some reflection and/or analysis, you need to type your parameters as Expression<T>. For example: Expression<Func<int>>. This turns your expression into an expression tree.
Expression trees enable you to access the expression like a data structure. Once you've finished analyzing your expression tree, you can call yourExpression.Compile(), and this will compile your expression tree into a delegate that can be invoked as any other delegate (either named and anonymous ones).
For example, obj1 would be accessed this way:
public class MyClass
{
public int Value { get; set; }
}
static void Main(string[] args)
{
var obj1 = new MyClass { Value = 1 };
var obj2 = new MyClass { Value = 2 };
Expression<Func<int>> expr = () => obj1.Value + obj2.Value;
BinaryExpression binaryExpr = (BinaryExpression)expr.Body;
MemberExpression memberExpr = (MemberExpression)binaryExpr.Left;
MemberExpression fieldExpr = (MemberExpression)memberExpr.Expression;
ConstantExpression constantExpr = (ConstantExpression)fieldExpr.Expression;
dynamic value = constantExpr.Value;
MyClass some = value.obj1;
}
Update
OP said in some comment:
unfortunately, changing from parameter Func to
Expression> doesnt seem to work well in my situation because,
expression tree is restricting my function delegate definition from
using assignment operators and statement body.
My answer to this is you want an unexisting universal solution, because any other solution might compromise maintainability.
Maybe there's an alternative that will allow you to stay with delegates instead of expression trees: a delegate with an out parameter which would contain a collection of objects involved in there...
Since standard BCL Func delegates don't come with output parameters, you can declare your own Func delegate as follows:
public delegate TResult Func<out T>(out IDictionary<string, object> objects);
...and your delegate should set the so-called out parameter:
using System;
using System.Collections.Generic;
public class Program
{
public class MyClass
{
public int Value { get; set; }
}
public delegate void Func<out T>(out IDictionary<string, object> objects);
public static void Main()
{
Func<int> someFunc = (out IDictionary<string, object> objects) =>
{
var obj1 = new MyClass { Value = 1 };
var obj2 = new MyClass { Value = 2 };
int result = obj1.Value + obj2.Value;
objects = new Dictionary<string, object> { { "obj1", obj1 }, { "obj2", obj2 } };
};
IDictionary<string, object> objectsInFunc;
someFunc(out objectsInFunc);
}
}
As written, it cannot be done, because you're trying to access information about the exact code and would thus need to examine the incoming IL (since the actual C# code is gone after compilation).
However, it WOULD be possible using the metacode libraries of System.Linq.Expression namespace, but only if you swap out Func<int> for Expression<Func<int>>. With this, you would then be able to walk the expressions tree created by your lambda call. Using an Expression in place of another delegate type also tells the compiler to make an expression tree, rather than actually compiling the code, so this won't work if you pass a direct method or try to examine non-expression tree objects the same way.
You can if you change the parameter type of Process to Expression<Func<int>> expr:
public static void Process(Expression<Func<int>> expr)
{
Func<int> function = expr.Compile();
var total = function();
Expression left = ((BinaryExpression)expr.Body).Left;
Expression leftObjExpr = ((MemberExpression)left).Expression;
Expression<Func<MyClass>> leftLambda =
Expression.Lambda<Func<MyClass>>(leftObjExpr);
Func<MyClass> leftFunc = leftLambda.Compile();
MyClass obj1 = leftFunc();
int value = obj1.Value; // ==> 10
// Same with right operand...
}
Note that you can still invoke the function; you just have to compile the lambda expression to get a callable function.
However, this will only work with a binary expression. If you want to parse all kinds of expressions, this becomes quite complicated. You best solve this problem with the Visitor pattern.
I am trying to make dynamic expression and assign lambda to it. As a result, I got exception:
System.ArgumentException: Expression of type 'Test.ItsTrue' cannot be used for assignment to type 'System.Linq.Expressions.Expression`1[Test.ItsTrue]'
What is wrong?
public delegate bool ItsTrue();
public class Sample
{
public Expression<ItsTrue> ItsTrue { get; set; }
}
[TestClass]
public class MyTest
{
[TestMethod]
public void TestPropertySetWithExpressionOfDelegate()
{
Expression<ItsTrue> itsTrue = () => true;
// this works at compile time
new Sample().ItsTrue = itsTrue;
// this does not work ad runtime
var new_ = Expression.New(typeof (Sample));
var result = Expression.Assign(
Expression.Property(new_, typeof (Sample).GetProperties()[0]),
itsTrue);
}
}
The second argument of Expression.Assign is the expression representing the value to assign. So currently you're effectively trying to assign an ItsTrue to the property. You need to wrap it so that it's an expression returning the value itsTrue... either via Expression.Quote or Expression.Constant. For example:
var result = Expression.Assign(
Expression.Property(new_, typeof (Sample).GetProperties()[0]),
Expression.Constant(itsTrue, typeof(Expression<ItsTrue>)));
Alternatively, you might want Expression.Quote - it really depends on what you're trying to achieve.
Here are my interfaces and enum, dumbed down slightly. :
public interface IExpression
{
ExpressionType ExpressionType { get; }
}
public interface ILiteralExpression : IExpression
{
object Value { get; set; }
}
public interface IOperatorExpression : IExpression
{
IExpression[] Operands { get; set; }
string OperatorUniqueName { get; set; }
IOperatorExpression SetOperand(int index, IExpression expression);
}
public enum ExpressionType
{
Operator,
Literal
}
To create an expression, I can do something like this:
var expression = ExpressionManager.Engines["Default"].Parser.Parse("1 + 3 * 4 + \"myVariable\"");
Which is equivalent to something like this:
var expression1 = ExpressionManager.CreateOperator("Add", 2).
SetOperand(0, ExpressionManager.CreateOperator("Add", 2).
SetOperand(0, ExpressionManager.CreateLiteral(1)).
SetOperand(1, ExpressionManager.CreateOperator("Multiply", 2).
SetOperand(0, ExpressionManager.CreateLiteral(3)).
SetOperand(1, ExpressionManager.CreateLiteral(4)))).
SetOperand(1, ExpressionManager.CreateLiteral("myVariable"));
I'd like to be able to do something like this (efficiently):
(from e in expression
where e is ILiteralExpression && "myVariable".Equals(((ILiteralExpression)e).Value)
select (ILiteralExpression)e).ToList().
ForEach(e => e.Value = 2);
I think I need to do some implementing of IQueryable or something, but I'm not sure where to start. Any suggestions?
Walk your expression tree, and convert each element to an object from the System.Linq.Expressions namespace, using the factory methods of the Expression class.
If you cannot modify your IExpression class to add methods that let you implement the visitor pattern, you can rely on type checking the old style:
private static Expression ConvertExpression(IExpression expr) {
if (expr is ILiteralExpression) {
return Expression.Constant(((ILiteralExpression)expr).Value);
}
if (expr is IOperatorExpression) {
var ops = ((IOperatorExpression)expr)
.Operands
.Select(ConvertExpression)
.ToList();
var res = ops[0];
for (int i = 1 ; i != ops.Length ; i++) {
if (((IOperatorExpression)expr).OperatorUniqueName == "+") {
res = Expressions.Add(res, ops[i]);
} else if (((IOperatorExpression)expr).OperatorUniqueName == "-") {
res = Expressions.Subtract(res, ops[i]);
} else if (...) {
}
}
return res;
}
}
Of course you'll need a lot more logic in this method. The crucial part is passing parameters: you need to figure out where your variables are and what is their type, use Expression.ParameterExpression to create it, and then compile your converted expression into a Func<...> of some sort using the LambdaExpression.Compile method. With a compiled lambda in hand, you can plug in your expressions into LINQ's in-memory framework.
If you can make your IExpressions visitable, add a visitor that walks the expression and converts it to a LINQ expression using a stack.
What you're looking to do is build your own LINQ Query Provider. You can choose what LINQ operations you want to allow (WHERE, OrderBy, etc.)
This is the blog post series that helped me the most when I wrote one:
http://blogs.msdn.com/b/mattwar/archive/2007/07/30/linq-building-an-iqueryable-provider-part-i.aspx