--- /dev/null
+// Do you allow this program?
+
+blaat(x) :: [a] -> Bool
+{
+ return True;
+}
+
+f()
+{
+ // This tries to assign to the built-in function isEmpty.
+ // Adapt this line if your isEmpty is called differently.
+ isEmpty = blaat;
+}
--- /dev/null
+// Depending on your design decisions this might or might not compile.
+// In our course we don't require higher-order functions.
+// In fact, our grammar doesn't even allow function types in type signatures.
+// Anyway, this could be an idea for assignment 4.
+
+map(f, list)
+// This doesn't parse according to our grammar
+// :: (a -> b) [a] -> [b]
+{
+ if( isEmpty(list) )
+ return [];
+ else
+ return f(list.hd) : map(f, list.tl);
+}
+
+foldl(f, z, list)
+{
+ if( isEmpty(list) )
+ return z;
+ else
+ return foldl(f, f(z, list.hd), list.tl);
+}
+
+// Some operators wrapped in a function.
+plus(x, y) { return x + y; }
+and(b, c) { return b && c; }
+ge18(x) { return x >= 18; }
+
+// Sums all the elements of an Int list.
+sum(list) { return foldl(plus, 0, list); }
+
+// Checks whether all elements in a list of Booleans are True
+all(list) { return foldl(and, True, list); }
+
+// Checks whether in a list of numbers everybody is older than 18
+allOlderThan18(list) { return all(map(ge18, list)); }
+
+main() { return; }
--- /dev/null
+// Various versions of the identity function
+
+// Identity for integers
+// The type signature forces the function to have a more concrete type than it could have.
+id_int(x) :: Int -> Int
+{
+ return x;
+}
+
+
+// Polymorphic identity with type signature
+id_poly_with(x) :: a -> a
+{
+ return x;
+}
+
+
+// Polymorphic identity without type signature
+// Type checking should figure out the type forall a . a -> a
+id_poly_without(x)
+{
+ return x;
+}
+
+
+// Clumsy polymorphic identity
+// Type checking should give type forall a . a -> a
+id_poly_wtf(x)
+{
+ var a = x;
+ var b = a;
+ var c = b;
+ return c;
+}
+
+
+// Clumsy identity for integers
+// Type checking should give type Int -> Int
+id_int_wtf(x)
+{
+ var a = x;
+ Int b = a;
+ var c = b;
+ return c;
+}
--- /dev/null
+// An example from the slides. This should give a type error.
+
+f(x)
+{
+ return f( (x, x) );
+}
--- /dev/null
+// Generates a list of zeros and ones
+
+flip(n, l)
+{
+ if( n <= 0 )
+ return l;
+ else
+ return flop(n-1, 0:l);
+}
+
+flop(n, l)
+{
+ return flip(n, 1:l);
+}
--- /dev/null
+// Do you allow this?
+// Explain why or why not.
+
+var ones = 1:ones;
+
+var flip = 0:flop;
+var flop = 1:flip;
+
+// What about this?
+var flup = (flap.hd):flup;
+var flap = (flup.hd):flap;
+
+
+
+// For testing
+take(n, list)
+{
+ if( n <= 0 )
+ return [];
+ else
+ return list.hd : take(n-1, list.tl);
+}
+
+main() { print(take(10,flip)); }
--- /dev/null
+// At this point you maybe don't see what the problem is.
+// Wait until you try to implement your code generator.
+
+equal(x, y)
+{
+ return x == y;
+}
--- /dev/null
+// Another variant of the polymorphic value problem.
+
+// This is perfectly fine
+var tuple1 = (1:[], True:[]);
+
+// This should fail.
+var l = [];
+var tuple2 = (1:l, True:l);
+
+
+main() { return; }
--- /dev/null
+// This is an example why you need the value restriction.
+// This program should give a type error in some way.
+
+// The empty list [] usually has polymorphic type forall a.[a], but you
+// cannot give the variable l this type. See below what can go wrong.
+var l = [];
+
+f()
+{
+ // If l has polymorphic type forall a . [a], the next two lines are possible.
+ l = 1:l;
+ l = True:l;
+ return;
+}
--- /dev/null
+// Greatest common divisor,
+// "The granddaddy of all algorithms, because it is the oldest nontrivial
+// algorithm that has survived to the present day." -- Don Knuth
+
+// This one only works for positive n, m
+gcd(m, n)
+{
+ if( n < m )
+ return gcd(n, m);
+ else if( n == m )
+ return n;
+ else // n > m
+ return gcd(m, n - m);
+}
--- /dev/null
+// A classic from computer science.
+// The function \x.x x can not be typed in let-polymorphic type systems.
+f(x)
+{
+ return x(x);
+}
--- /dev/null
+// Uncomment lines one by one. How far can you take your compiler?
+
+f0(x) { return (x, x); }
+f1(x) { return f0(f0(x)); }
+// f2(x) { return f1(f1(x)); }
+// f3(x) { return f2(f2(x)); }
+// f4(x) { return f3(f3(x)); }
+// f5(x) { return f4(f4(x)); }
>>= \mt->case mt of
Nothing = liftT $ Left $ UndeclaredVariableError p ident
Just t = unify t fs
-
typeOp2 :: Expr Expr Op2 [Type] Type -> Env Type
typeOp2 e1 e2 op ts ret = typeExpr e1 >>= \t1-> typeExpr e2 >>= \t2->
unify t1 t2 >>= \t3->if (isMember t3 ts) (pure ret)