Search code examples
dependent-typeats

Dependent types over datatypes


I struggled for a bit with writing a function that could only be passed certain days of the week. I expected that this would work:

datatype days = sunday | monday | tuesday | wednesday | thursday | friday | saturday

fn only_sunday{d:days | d == sunday}(d: days(d)): days(d) = d

but of course, days(d) was never even defined. That only seemed like it would work because ATS has so many builtin types - int and also int(int), etc.

This also doesn't work, but perhaps it's just the syntax that's wrong?

typedef only_sunday = { d:days | d == sunday }

fn only_sunday(d: only_sunday): only_sunday = d

After revisiting the Dependent Types chapter of Introduction to Programming in ATS, I realized that this works:

datatype days(int) =
  | sunday(0)
  | monday(1)
  | tuesday(2)
  | wednesday(3)
  | thursday(4)
  | friday(5)
  | saturday(6)

fn print_days{n:int}(d: days(n)): void =
  print_string(case+ d of
    | sunday() => "sunday"
    | monday() => "monday"
    | tuesday() => "tuesday"
    | wednesday() => "wednesday"
    | thursday() => "thursday"
    | friday() => "friday"
    | saturday() => "saturday")
overload print with print_days

fn sunday_only{n:int | n == 0}(d: days(n)): days(n) = d

implement main0() =
  println!("this typechecks: ", sunday_only(sunday))

but of course, it's a little bit less clear that n == 0 means "the day must be sunday" than it would with some code like d == sunday. And although it doesn't seem that unusual to map days to numbers, consider:

datatype toppings(int) = lettuce(0) | swiss_cheese(1) | mushrooms(2) | ...

In this case the numbers are completely senseless, such that you can only understand any {n:int | n != 1} ... toppings(n) code as anti-swiss-cheese if you have the datatype definition at hand. And if you were to edit in a new topping

datatype toppings(int) = lettuce(0) | tomatoes(1) | swiss_cheese(2) | ...

then it would be quite a chore update 1 to 2 in only any Swiss cheese code.

Is there a more symbolic way to use dependent types?


Solution

  • You could try something like this:

    stadef lettuce = 0
    stadef swiss_cheese = 1
    stadef mushrooms = 2
    
    datatype
    toppings(int) =
    | lettuce(lettuce)
    | swiss_cheese(swiss_cheese)
    | mushrooms(mushrooms)