am hoping some Haskell experts can help clarify something.
Is it possible to define Nat
in the usual way (via @dorchard Singleton types in Haskell)
data S n = Succ n
data Z = Zero
class Nat n
instance Nat Z
instance Nat n => Nat (S n)
(or some variant thereof) and then define a LessThan
relation
such that forall n
and m
LessThan Z (S Z)
LessThan n m => LessThan n (S m)
LessThan n m => LessThan (S n) (S m)
and then write a function with a type like:
foo :: exists n. (LessThan n m) => Nat m -> Nat n
foo (S n) = n
foo Z = foo Z
I explicitly want to use the "LessThan" in the output type for foo
,
I realize that one could certainly write something like
foo :: Nat (S n) -> Nat n
but thats not what I'm after.
Thanks!
Ranjit.
Here's one way to implement something similar to what you ask about.
First note that you define Nat
as a class and then use it as a type. I think it makes sense to have it as a type, so let's define it as such.
data Z
data S n
data Nat n where
Zero :: Nat Z
Succ :: Nat n -> Nat (S n)
We can also define LessThan
as a type.
data LessThan n m where
LT1 :: LessThan Z (S Z)
LT2 :: LessThan n m -> LessThan n (S m)
LT3 :: LessThan n m -> LessThan (S n) (S m)
Note that I just toke your three properties and turned them into data constructors. The idea of this type is that a fully normalized value of type LessThan n m
is a proof that n
is less than m
.
Now you ask about:
foo :: exists n. (LessThan n m) => Nat m -> Nat n
But there exists no exists in Haskell. Instead, we can define a datatype just for foo
:
data Foo m where
Foo :: Nat n -> LessThan n m -> Foo m
Note that n
is effectively existenially quantified here, because it shows up in the arguments of the data constructor Foo
but not in its result. Now we can state the type of foo
:
foo :: Nat m -> Foo m
Before we can implement the example from the question, we have to prove a little lemma about LessThan
. The lemma says that n
is less than S n
for all n
. We prove it by induction on n
.
lemma :: Nat n -> LessThan n (S n)
lemma Zero = LT1
lemma (Succ n) = LT3 (lemma n)
Now we can write the code from the question:
foo :: Nat m -> Foo m
foo (Succ n) = Foo n (lemma n)
foo Zero = foo Zero
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With