In addition, the [type-sig] is optional, in which case a bit of type inference is implemented.
Because mirth is contextual, the type inference makes a few useful assumptions based on the name:
if you're writing a type-qualified word that looks like a method, e.g. List.my-method, then it assumes that qualifying type is the top input: *? List(?) -- *?
if you're writing a type-qualified word that looks like a constructor, e.g. List.SuperCons, then it assumes that qualifying type is the top output, *? -- *? List(?). (By the way, "looks like a constructor" means it's a qualified word that starts with an uppercase letter. "Looks like a method" is everything else.)
if you're writing a word called main within a module, it assumes you want the type signature +World -- +World.
if your word takes parameters, it adds those to the type signature, e.g. foo(f) would get a type signature (*? -- *?) *? -- *?
These asumptions help us avoid the need to write explicit type annotations in many situations, because having a little bit of type information (e.g. when defining a method) helps a lot with name resolution.
Ultimately the goal here isn't to get the most general type, it's to get the type the user wants most of the time. If the user wants something else, they can always write a type signature.
Also there is some support for recursive definitions. But it's always going to be much harder to infer those, especially because of stack polymorphism. Again, one can always write a type signature.
This PR adds a new
def
syntax:which is sugar for
def(word, type-sig, body)
.In addition, the
[type-sig]
is optional, in which case a bit of type inference is implemented.Because mirth is contextual, the type inference makes a few useful assumptions based on the name:
if you're writing a type-qualified word that looks like a method, e.g.
List.my-method
, then it assumes that qualifying type is the top input:*? List(?) -- *?
if you're writing a type-qualified word that looks like a constructor, e.g.
List.SuperCons
, then it assumes that qualifying type is the top output,*? -- *? List(?)
. (By the way, "looks like a constructor" means it's a qualified word that starts with an uppercase letter. "Looks like a method" is everything else.)if you're writing a word called
main
within a module, it assumes you want the type signature+World -- +World
.if your word takes parameters, it adds those to the type signature, e.g.
foo(f)
would get a type signature(*? -- *?) *? -- *?
These asumptions help us avoid the need to write explicit type annotations in many situations, because having a little bit of type information (e.g. when defining a method) helps a lot with name resolution.
Ultimately the goal here isn't to get the most general type, it's to get the type the user wants most of the time. If the user wants something else, they can always write a type signature.
Also there is some support for recursive definitions. But it's always going to be much harder to infer those, especially because of stack polymorphism. Again, one can always write a type signature.