In the following, example1
is standard syntax (as documented), with Eq a
as a constraint. In example2
, I specify Eq a
directly as the type of a parameter, and the compiler accepts it. However it is unclear what I can specify as a value of that type. For a specific type a
, eg Nat
, I assume it would make sense to somehow specify an implementation of Eq Nat
, either the default implementation, or some other named implementation.
%default total
example1: Eq a => (x : a) -> (y : a) -> Type
example1 {a} x y = ?example1_rhs
example1b: Eq a => (x : a) -> (y : a) -> Type
example1b {a} x y = x == y = True
example2: (a : Type) -> Eq a -> (x : a) -> (y : a) -> Type
example2 a eqa x y = ?example2_rhs
example2b: (a : Type) -> Eq a -> (x : a) -> (y : a) -> Type
example2b a eqa x y = x == y = True
eq_nat : Eq Nat
eq_nat = ?eq_nat_rhs
example_of_example2 : Type
example_of_example2 = example2 Nat eq_nat 3 3
Resulting holes:
- + Main.example1_rhs [P]
`-- a : Type
x : a
y : a
constraint : Eq a
--------------------------
Main.example1_rhs : Type
- + Main.example2_rhs [P]
`-- a : Type
eqa : Eq a
x : a
y : a
--------------------------
Main.example2_rhs : Type
- + Main.eq_nat_rhs [P]
`-- Eq Nat
As far as I can tell, I can't actually use example2b
as a function unless I have some way to specify a value for the second parameter of type Eq a
.
There are situations where it would be genuinely useful to be able to apply an interface constraint to the value of a parameter (as opposed to the type of a parameter), so I'm hoping that this is a valid feature of Idris.
There are also several data types declared in the library, including Bool , with values True and False. We can declare some constants with these types. Enter the following into a file Prims.idr and load it into the Idris interactive environment by typing idris2 Prims.idr:
In Idris, types are first class, meaning that they can be computed and manipulated (and passed to functions) just like any other language construct. For example, we could write a function which computes a type:
When writing Idris programs both the order in which definitions are given and indentation are significant. Functions and data types must be defined before use, incidentally each definition must have a type declaration, for example see x : Int, foo : String, from the above listing.
Idris will, in general, try to disambiguate which operators you mean by type, but you can explicitly choose with qualified do notation, for example: The Prelude.do means that Idris will use the (>>=) and (>>) operators defined in the Prelude. Sometimes we want to pattern match immediately on the result of a function in do notation.
You could use named implementations:
[eq_nat] Eq Nat where { ... }
...
example_of_example2 : Type
example_of_example2 = example2 Nat eq_nat 3 3
A useful application of named implementations are defining multiple implementation of Monoid
:
[PlusNatSemi] Semigroup Nat where
(<+>) x y = x + y
[MultNatSemi] Semigroup Nat where
(<+>) x y = x * y
[PlusNatMonoid] Monoid Nat using PlusNatSemi where
neutral = 0
[MultNatMonoid] Monoid Nat using MultNatSemi where
neutral = 1
To comment : To get the default instance
getEq : (a : Type) -> {auto inst : Eq a} -> Eq a
getEq a {inst} = inst
Then you can have your default instance:
getEq (List Nat) -- => implementation of Eq...
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