unisonweb / unison

A friendly programming language from the future
https://unison-lang.org
Other
5.73k stars 266 forks source link

Too many different hashes for variations of a term? #3328

Open mitchellwrosen opened 2 years ago

mitchellwrosen commented 2 years ago

~I'm not sure if there's a bug here, but it would be good to capture this information in a transcript test (or confirm that we already have one).~ Wait, read on, I think there's definitely at least one bug lurking.

Here are a bunch of similar ways to ascribe a type to a suspended a term (in this example, foo = '175). Each group corresponds to a term with a different hash.

Group 1

User-written signature Pretty-printed type
(No explicit type signature) 'Nat
a ->{} Nat 'Nat

Group 2

User-written signature Pretty-printed type
'Nat 'Nat
() -> Nat 'Nat
() ->{} Nat 'Nat

Group 3

User-written signature Pretty-printed type
() ->{e} Nat 'Nat

Group 4

User-written signature Pretty-printed type
() ->{e1,e2} Nat 'Nat
Group 5 User-written signature Pretty-printed type
a -> Nat a -> Nat
a ->{e} Nat a -> Nat
Group 6 User-written signature Pretty-printed type
a ->{e1,e2} Nat a -> Nat

And a couple thoughts:

mitchellwrosen commented 2 years ago

cc @dolio, just want to make sure this is on your radar, if it seems relevant to you :stuck_out_tongue:

dolio commented 2 years ago

Which part is the buggy seeming part?

A lot of this is the pretty printer hiding information. I think there's a way to get it to print the exact type, but I don't recall what it is.

Adding ability variables to 'positive' ability lists gives equivalent types, and the pretty printer leaves those out. It also leaves out such ability lists entirely when they're equivalent to empty lists, because those are considered analogous to "pure" functions. In the one direction:

a ->{} b ==> forall e1 e2 e3 ... . a ->{e1,e2,e3...} b

because you can always add redundant abilities that the function doesn't really require. In the opposite direction, you can just instantiate all those variables to {}. The quantification ensures the function doesn't really use them, essentially.

It is unfortunate that these all yield different hashes. I think there's some tension with trying to canonicalize the types that people explicitly write, though. Maybe that isn't that important, though, because the pretty printer already shows a different type than the one you explicitly give in these cases.