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
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