package nl.utwente.viskell.haskell.expr;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import nl.utwente.viskell.haskell.type.FunType;
import nl.utwente.viskell.haskell.type.HaskellTypeError;
import nl.utwente.viskell.haskell.type.Type;
import nl.utwente.viskell.haskell.type.TypeScope;
import java.util.List;
public class Lambda extends Expression {
/** The list of variable binders in this lambda */
private final List<Binder> binders;
/** The expression in the body of this lambda */
private final Expression body;
/**
* @param binders The list of variable binders in this lambda, should be at least one
* @param body The expression in the body of this lambda
*/
public Lambda(List<Binder> binders, Expression body) {
this.binders = binders;
this.body = body;
}
@Override
public Type inferType() throws HaskellTypeError {
TypeScope scope = new TypeScope();
// Rule [Abs]:
// assign the binder fresh type variable (x)
for (Binder x : this.binders) {
x.refreshBinderType(scope);
}
// infer the type (y) for the body with the type variable in the context
Type type = this.body.inferType();
// then lambda has the function type (x -> y)
for (Binder x : Lists.reverse(this.binders)) {
type = new FunType(x.getBoundType(), type);
}
return type;
}
@Override
public String toHaskell() {
StringBuilder out = new StringBuilder();
out.append("(\\");
for (Binder x : this.binders) {
out.append(" ").append(x.getUniqueName());
}
if (this.binders.isEmpty()) {
out.append("_");
}
out.append(" -> ");
out.append(this.body.toHaskell());
out.append(")");
if (this.binders.isEmpty()) {
out.append(" ()");
}
return out.toString();
}
@Override
public String toString() {
StringBuilder out = new StringBuilder();
out.append("(\\");
for (Binder x : this.binders) {
out.append(" ").append(x.getBaseName());
}
if (this.binders.isEmpty()) {
out.append("_");
}
out.append(" -> ");
out.append(this.body.toString());
out.append(")");
if (this.binders.isEmpty()) {
out.append(" ()");
}
return out.toString();
}
@Override
public List<Expression> getChildren() {
return ImmutableList.of(body);
}
}