anchor.diff:      Int = {id,As,"int"},
       Bool = {id,As,"bool"},
       {fun_t,As,[Int,Int],Bool}.
  +    {fun_t,As,[Int,Int],Bool};
  +infer_infix({'::',As}) ->
  +    ElemType = fresh_uvar(As),
  +    ListType = {app_t,As,{id,As,"list"},[ElemType]},
  +    {fun_t,As,[ElemType,ListType],ListType}.
   
   unify(T1,T2) ->
     unify1(dereference(T1),dereference(T2)).
  
positive.code:     true;
  unify1({fun_t,_,Args1,Result1},{fun_t,_,Args2,Result2}) ->
      unify(Args1,Args2) andalso unify(Result1,Result2);
  unify1(A,B) ->
      cannot_unify(A,B),
      false.
  
negative.code: 
  
  cannot_unify(A,B) ->
      create_uvar_names(),
      io:format("Cannot unify ~s (from line ~p)\n"
  	      "         and ~s (from line ~p)\n",
  	      [pp(A),line_number(A),pp(B),line_number(B)]),
      destroy_uvar_names().
  
  line_number(T) when is_tuple(T) ->
      proplists:get_value(line,element(2,T)).
  
  pp({type_sig,As,B}) ->
      ["(",pp(As),") => ",pp(B)];
  pp([]) ->
      "";
  pp([T]) ->
      pp(T);
  pp([T|Ts]) ->
      [pp(T),", "|pp(Ts)];
  pp({id,_,Name}) ->
      Name;
  pp({tvar,_,Name}) ->
      Name;
  pp({uvar,_,R}) ->
      uvar_name(R);
  pp({tuple_t,_,Cpts}) ->
      ["(",pp(Cpts),")"];
  pp({app_t,_,{id,_,Name},Args}) ->
      [Name,"(",pp(Args),")"].
  
  create_uvar_names() ->
      ets:new(uvar_names,[named_table,public,set]),
      ets:insert(uvar_names,{next,1}).
  
  uvar_name(R) ->
      case ets:lookup(uvar_names,R) of
  	[] ->
  	    [{next,N}] = ets:lookup(uvar_names,next),
  	    ets:insert(uvar_names,[{next,N+1},{R,N}]);
  	[{R,N}] ->
  	    ok
      end,
      ["'_",integer_to_list(N)].
  
  destroy_uvar_names() ->
      ets:delete(uvar_names).
  