How to constraint input type and output type to be the same? - type-safety

I am going through Type driven development with Idris from Manning. An example is given that teaches how to restrict a function to a given type in a family of types. We have Vehicle type that uses PowerSource that is either Pedal or Petrol and we need to write a function refill that typechecks only for vehicles that use petrol as their powersource.
The below code works, but does not guarantee that refilling a Car will produce a Car and not a Bus. How do I need to change the signature of the refill function to only allow producing Car when given a Car and producing Bus when given Bus?
data PowerSource
= Pedal
| Petrol
data Vehicle : PowerSource -> Type
where
Bicycle : Vehicle Pedal
Car : (fuel : Nat) -> Vehicle Petrol
Bus : (fuel : Nat) -> Vehicle Petrol
refuel : Vehicle Petrol -> Nat -> Vehicle Petrol
refuel (Car fuel) x = Car (fuel + x)
refuel (Bus fuel) x = Bus (fuel + x)

This can be achieved by introducing new VehicleType data type and by adding one more parameter to Vehicle like this:
data VehicleType = BicycleT | CarT | BusT
data Vehicle : PowerSource -> VehicleType -> Type
where
Bicycle : Vehicle Pedal BicycleT
Car : (fuel : Nat) -> Vehicle Petrol CarT
Bus : (fuel : Nat) -> Vehicle Petrol BusT
You should somehow encode in type difference between constructors. If you want more type safety you need to add more information to types. Then you can use it to implement refuel function:
refuel : Vehicle Petrol t -> Nat -> Vehicle Petrol t
refuel (Car fuel) x = Car (fuel + x)
refuel (Bus fuel) x = Bus (fuel + x)
Replacing
refuel (Car fuel) x = Car (fuel + x)
with
refuel (Car fuel) x = Bus (fuel + x)
leads to next type error:
Type checking ./Fuel.idr
Fuel.idr:14:8:When checking right hand side of refuel with expected type
Vehicle Petrol CarT
Type mismatch between
Vehicle Petrol BusT (Type of Bus fuel)
and
Vehicle Petrol CarT (Expected type)
Specifically:
Type mismatch between
BusT
and
CarT

Another possibility is to do what you want externally. It might be an option when you cannot change the original type, e.g. if it comes from a library. Or if you do not want to clutter your type with too many extra indices which you might want to add to state more properties.
Let us reuse the VehicleType type introduced by #Shersh:
data VehicleType = BicycleT | CarT | BusT
Now, let's define a function which tells us which constructor was used to construct a vehicle. It allows us to state our property quit consice:
total
vehicleType : Vehicle t -> VehicleType
vehicleType Bicycle = BicycleT
vehicleType (Car _) = CarT
vehicleType (Bus _) = BusT
And now we can say that refuel preserves the type of a vehicle:
total
refuelPreservesVehicleType : vehicleType (refuel v x) = vehicleType v
refuelPreservesVehicleType {v = (Car _)} = Refl
refuelPreservesVehicleType {v = (Bus _)} = Refl

Related

Ways to handle collections of interfaces with generic lambdas

I am currently trying to experiment with F# and I am struggling a bit with how to best handle a scenario such as described with these types:
[<Interface>]
type IStuff<'a> =
abstract member Update: 'a -> 'a
type Stuff1<'a> = {
Pos : int
Sprite : string
Temperature : float
UpdateBehaviour : 'a -> 'a
} with
interface IStuff<'a> with
member this.Update p =
this.UpdateBehaviour p
static member New f = {
Pos = 0
Sprite = "Sprite"
Temperature = 0.0
UpdateBehaviour = f
}
type Stuff2<'a> = {
Pos : int
UpdateBehaviour : 'a -> 'a
} with
interface IStuff<'a> with
member this.Update p =
this.UpdateBehaviour p
static member New f = {
Pos = 0
UpdateBehaviour = f
}
Now ideally I would like to have both Stuff1 and Stuff2 types together in a collection where each particle would call its specific update function which may change based on the type (as types have varying fields of data) or simply differs between the same types.
I have tried multiple things with approaches such as this.
let stuffArr< 'T when 'T :> IStuff<'T>> = [|
Stuff1.New<_> (fun p -> printfn "s1"; p)
Stuff2.New<_> (fun p -> printfn "s2"; p)
|]
Which obviously does not function as the compiler identifies that these two are clearly different types with Stuff1 being type ´aand Stuff2 being type ´b.
I could also do an approach such as this.
let stuffArr : obj list = [
Stuff1.New<_> (fun p -> printfn "p1"; p)
Stuff2.New<_> (fun p -> printfn "p2"; p)
]
let iterateThrough (l : obj list) =
l
|> List.map (fun p ->
let s = p :?> IStuff<_>
s.Update p)
Which functions obviously but as you all may now, I essentially turn off the type system and I am doing a dynamic down cast which frankly scares me.
So is there a better way to accomplish this? Thanks in advance!
There are ways to get a bit more checking with the structure you have, but none of those are very nice. However, I think that the fundamental issue is that you are trying to use F# as an object-oriented language. If you use a more functional design, this will look much nicer.
I would define Stuff as a discriminated union with the different kinds of stuff:
type Stuff =
| Stuff1 of pos:int * sprite:string * temperature:float
| Stuff2 of pos:int
let stuffArr = [
Stuff1(0, "Sprite", 0.0)
Stuff2(0)
]
The update operation would then be just a function that uses pattern matching to handle the two different kinds of stuff you have:
let update stuff =
match stuff with
| Stuff1 _ -> ...
| Stuff2 _ -> ...
The result is that you can update all stuff and get a new list using just List.map:
List.map update stuffArr
I get the feeling that what you're showing above may not have the same complexity as what you're actually trying to do. If that's the case, Tomas' solution may be too simple for you to use. If you have some reason to prefer using the interface you described above, you could define stuffArr as follows
let stuffArr : IStuff<_>[] = [|
Stuff1.New<int> (fun p -> printfn "s1"; p)
Stuff2.New<int> (fun p -> printfn "s2"; p)
|]
Here I assumed the generic parameter to be int. It could be any other type - I assume you have something in mind. However, the generic parameter for each entry in the array needs to be the same. If you need different generic parameters, you would need to wrap them in a discriminated union like so
type MyWrapper = String of string | Int of int
let stuffArr : IStuff<_>[] = [|
Stuff1.New<MyWrapper> (fun p -> printfn "s1"; p)
Stuff2.New<MyWrapper> (fun p -> printfn "s2"; p)
|]
or using the build-in Choice type
let stuffArr : IStuff<_>[] = [|
Stuff1.New<Choice<string, int>> (fun p -> printfn "s1"; p)
Stuff2.New<Choice<string, int>> (fun p -> printfn "s2"; p)
|]

What are the rules of Coq implicit types deduction in Inductive definitions?

Consider this type that has X as an implicit type.
Inductive list' {X:Type} : Type :=
| nil'
| cons' (x : X) (l : list').
Coq deduced that type of the second argument of cons' is #list' A:
Fail Check cons' a (cons' b nil'). (* "cons' b nil'" expected to have type "#list' A"*)
But how was this type deduced unambiguously?
We can create another type:
Inductive list'' {X:Type} : Type :=
| nil''
| cons'' (x : X) (l : #list'' B).
Check cons'' a (cons'' b nil'').
It shows that l could also be #list' B.
To be precise, Coq inferred the type of cons' to be forall {X}, X -> #list' X -> #list' X. Then when you write cons a, Coq works out that you must be building a #list' A, and fills in X with A, thus constraining the second argument to be again of type #list' A.
However, the choice of X over some other type is not the only possible choice, as you noticed. In your second example, cons'' gets type forall {X}, X -> #list'' B -> #list'' X. However, when it is left unspecified, most people most of the time intend their parameters (things on the left side of the colon) to be uniform, that is, the same in the arguments as in the conclusion, which heuristic leads to the choice of X here. In general, Coq doesn't worry too much about making sure it's solutions are unique for things the user left unspecified.
In recent enough versions of Coq, you can use the option Uniform Inductive Parameters to specify that all parameters are uniform, or use a | to separate the uniform from the non-uniform parameters. In the case of lists, that would look like
Inductive list' (X:Type) | : Type :=
| nil'
| cons' (x : X) (l : list').
Note that with the |, in the declaration of constructors list' has type Type, while without the |, list' has type Type -> Type, and there is a constraint that the conclusion of the constructor has to be list X (while the arguments can use list other_type freely).

Retrieving constraints from GADT to ensure exhaustion of pattern matching in Coq

Let's define two helper types:
Inductive AB : Set := A | B.
Inductive XY : Set := X | Y.
Then two other types that depend on XY and AB
Inductive Wrapped : AB -> XY -> Set :=
| W : forall (ab : AB) (xy : XY), Wrapped ab xy
| WW : forall (ab : AB), Wrapped ab (match ab with A => X | B => Y end)
.
Inductive Wrapper : XY -> Set :=
WrapW : forall (xy : XY), Wrapped A xy -> Wrapper xy.
Note the WW constructor – it can only be value of types Wrapped A X and Wrapped B Y.
Now I would like to pattern match on Wrapper Y:
Definition test (wr : Wrapper Y): nat :=
match wr with
| WrapW Y w =>
match w with
| W A Y => 27
end
end.
but I get error
Error: Non exhaustive pattern-matching: no clause found for pattern WW _
Why does it happen? Wrapper forces contained Wrapped to be A version, the type signature forces Y and WW constructor forbids being A and Y simultaneously. I don't understand why this case is being even considered, while I am forced to check it which seems to be impossible.
How to workaround this situation?
Let's simplify:
Inductive MyTy : Set -> Type :=
MkMyTy : forall (A : Set), A -> MyTy A.
Definition extract (m : MyTy nat) : nat :=
match m with MkMyTy _ x => S x end.
This fails:
The term "x" has type "S" while it is expected to have type "nat".
wat.
This is because I said
Inductive MyTy : Set -> Type
This made the first argument to MyTy an index of MyTy, as opposed to a parameter. An inductive type with a parameter may look like this:
Inductive list (A : Type) : Type :=
| nil : list A
| cons : A -> list A -> list A.
Parameters are named on the left of the :, and are not forall-d in the definition of each constructor. (They are still present in the constructors' types outside of the definition: cons : forall (A : Type), A -> list A -> list A.) If I make the Set a parameter of MyTy, then extract can be defined:
Inductive MyTy (A : Set) : Type :=
MkMyTy : A -> MyTy A.
Definition extract (m : MyTy nat) : nat :=
match m with MkMyTy _ x => S x end.
The reason for this is that, on the inside, a match ignores anything you know about the indices of the scrutinee from the outside. (Or, rather, the underlying match expression in Gallina ignores the indices. When you write a match in the source code, Coq tries to convert it into the primitive form while incorporating information from the indices, but it often fails.) The fact that m : MyTy nat in the first version of extract simply did not matter. Instead, the match gave me S : Set (the name was automatically chosen by Coq) and x : S, as per the constructor MkMyTy, with no mention of nat. Meanwhile, because MyTy has a parameter in the second version, I actually get x : nat. The _ is really a placeholder this time; it is mandatory to write it as _, because there's nothing to match, and you can Set Asymmetric Patterns to make it disappear.
The reason we distinguish between parameters and indices is because parameters have a lot of restrictions—most notably, if I is an inductive type with parameters, then the parameters must appear as variables in the return type of each constructor:
Inductive F (A : Set) : Set := MkF : list A -> F (list A).
(* ^--------^ BAD: must appear as F A *)
In your problem, we should make parameters where we can. E.g. the match wr with Wrap Y w => _ end bit is wrong, because the XY argument to Wrapper is an index, so the fact that wr : Wrapper Y is ignored; you would need to handle the Wrap X w case too. Coq hasn't gotten around to telling you that.
Inductive Wrapped (ab : AB) : XY -> Set :=
| W : forall (xy : XY), Wrapped ab xy
| WW : Wrapped ab (match ab with A => X | B => Y end).
Inductive Wrapper (xy : XY) : Set := WrapW : Wrapped A xy -> Wrapper xy.
And now your test compiles (almost):
Definition test (wr : Wrapper Y): nat :=
match wr with
| WrapW _ w => (* mandatory _ *)
match w with
| W _ Y => 27 (* mandatory _ *)
end
end.
because having the parameters gives Coq enough information for its match-elaboration to use information from Wrapped's index. If you issue Print test., you can see that there's a bit of hoop-jumping to pass information about the index Y through the primitive matchs which would otherwise ignore it. See the reference manual for more information.
The solution turned out to be simple but tricky:
Definition test (wr : Wrapper Y): nat.
refine (match wr with
| WrapW Y w =>
match w in Wrapped ab xy return ab = A -> xy = Y -> nat with
| W A Y => fun _ _ => 27
| _ => fun _ _ => _
end eq_refl eq_refl
end);
[ | |destruct a]; congruence.
Defined.
The issue was that Coq didn't infer some necessary invariants to realize that WW case is ridiculous. I had to explicitly give it a proof for it.
In this solution I changed match to return a function that takes two proofs and brings them to the context of our actual result:
ab is apparently A
xy is apparently Y
I have covered real cases ignoring these assumptions, and I deferred "bad" cases to be proven false later which turned to be trivial. I was forced to pass the eq_refls manually, but it worked and does not look that bad.

RelationClasses versus CRelationClasses

The Coq standard library has two subsets of classes modules, one anchored in Coq.Classes.RelationClasses and the other in Coq.Classes.CRelationClasses. The latter seems to have been added more recently (2012).
I must be missing something obvious as they both look very similar to me.
What is the reason they exist?
The key difference is in the type of relations they support:
(* RelationClasses, actually defined in Relation_Definitions *)
Definition relation (A : Type) := A -> A -> Prop.
(* CRelationClasses *)
Definition crelation (A : Type) := A -> A -> Type.
In addition to crelation producing a Type instead of a Prop, another key difference is that crelation is universe polymorphic, but relation is not.
Require Import Relation_Definitions.
Require Import Coq.Classes.CRelationClasses.
Set Printing Universes.
Print relation.
(*
relation =
fun A : Type#{Coq.Relations.Relation_Definitions.1} => A -> A -> Prop
: Type#{Coq.Relations.Relation_Definitions.1} ->
Type#{max(Set+1,Coq.Relations.Relation_Definitions.1)}
*)
Print crelation.
(*
crelation#{u u0} =
fun A : Type#{u} => A -> A -> Type#{u0}
: Type#{u} -> Type#{max(u,u0+1)}
(* u u0 |= *)
*)
Check (fun (R: crelation (Type -> Type)) => R crelation).
Fail Check (fun (R: relation (Type -> Type)) => R relation).
(*
The command has indeed failed with message:
In environment
R : relation (Type#{test.7} -> Type#{test.8})
The term "relation" has type
"Type#{Coq.Relations.Relation_Definitions.1} ->
Type#{max(Set+1,Coq.Relations.Relation_Definitions.1)}"
while it is expected to have type "Type#{test.7} -> Type#{test.8}"
(universe inconsistency: Cannot enforce Coq.Relations.Relation_Definitions.1
<= test.8 because test.8 < Coq.Relations.Relation_Definitions.1).
*)

Is the %hint annotation imported/Dec and auto annotation?

I have a datatype that depends on a predicate P : a -> Type, meaning that some of its data constructors refer have an implicit P x as argument. I would like idris to be able to automatically infer this implicit. For this, I annotated the implicit with the keyword auto and I wrote a function isP : (x : a) -> Dec (P x) with a %hint annotation before the type declaration. Namely, something like:
module P
P : a -> Type
%hint
isP : (x : a) -> Dec (P x)
and in a separate file
module Main
import P
data Foo : Type where
Bar : (x : a) -> .{auto prf : P x} -> Foo
That said, I can't declare values of said Foo type because Idris claims the it can't infer prf.
Is this because prf has type P x instead of Dec (P x) or is it because the %hint flag does not get imported?
In either case, how can I get Idris to use a Dec value to try to find an implicit?
The %hint flag is imported, as you guess, it's because Dec (P x) is different than P x.
There's a trick though, you can use this datatype:
data IsYes : prop -> Type where
SoTrue : IsYes (Yes prop)
(basically, you define a type that holds a Yes for a given property)
and then you can use default instead of auto to check if the property holds:
data Foo : Type where
Bar : (x : a) -> .{default SoTrue prf : IsYes (isP x)} -> Foo
Note: with this trick, you don't even need %hint anymore, you just check the outcome of isP at compile time.