private static IType Infer(IDictionary<string, IType> env, INode node, IType[] known) { Func<INode, IType> taggedType = tagged => { if (!Type.Const.ContainsKey(tagged.Type)) { throw new InvalidOperationException(String.Format("unknown basic type : \"{0}\"", tagged.Type)); } return Type.Const[tagged.Type]; }; known = known ?? new IType[] {}; if ((node.Name is string) && (node.Args == null) && (node.Term == null)) { if (!env.ContainsKey((string) node.Name)) { throw new InvalidOperationException(String.Format("unknown identifier : \"{0}\"", node.Name)); } return Unifier.Fresh(env[(string) node.Name], known); } if ((node.Name == null) && (node.Type != null)) { return taggedType(node); } if ((node.Name is INode) && (node.Args != null) && (node.Term == null)) { List<IType> args = node.Args.Select(arg => Infer(env, arg, known)).ToList(); var type = new Var(); args.Add(type); Unifier.Unify(new Type(Type.Function, args.ToArray()), Infer(env, (INode) node.Name, known)); return type; } if ((node.Name is string) && (node.Args != null) && (node.Term is INode)) { // Optional: node.Type (string) List<IType> types = known.ToList(); var args = new List<IType>(); Type type; foreach (INode arg in node.Args) { IType var; if (arg.Type == null) { var = new Var(); types.Add(var); } else { var = taggedType(arg); } env[(string) arg.Name] = var; args.Add(var); } args.Add(Infer(env, (INode) node.Term, types.ToArray())); if (node.Type != null) { Unifier.Unify(args[args.Count - 1], taggedType(node)); } type = new Type(Type.Function, args.ToArray()); if (((string) node.Name).Length > 0) { env[(string) node.Name] = type; } return type; } if ((node.Name is string) && (((string) node.Name).Length > 0) && (node.Term is INode)) { // Optional: node.Type (string) IType type = Infer(env, (INode) node.Term, known); if (node.Type != null) { Unifier.Unify(type, taggedType(node)); } return (env[(string) node.Name] = type); } throw new ArgumentOutOfRangeException("node", "missing or invalid attribute(s)"); }