Data type that represents the proof that two functions are equivalent - idris

I was trying to make a data type that represents that fact that two functions are equivalent. What does the error mean?
Code:
record FEq (f1 : a -> b) (f2 : a -> b) where
constructor MkFEq
unFEq : (x : a) -> (f1 x = f2 x)
Error:
Type checking ./FEq.idr
FEq.idr:1:1-3:36:
|
1 | record FEq (f1 : a -> b) (f2 : a -> b) where
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ...
When checking type of Main.FEq.unFEq:
When checking argument x to type constructor =:
Type mismatch between
free_a b a f1 f2 rec
and
a

AFAIK you are not allowed to mention unbound parameters in a record.
So you have to add a and b as parameters like so:
record FEq a b (f1 : a -> b) (f2 : a -> b) where
constructor MkFEq
unFEq : (x : a) -> (f1 x = f2 x)

Related

Defining groups in Idris

I defined monoid in Idris as
interface Is_monoid (ty : Type) (op : ty -> ty -> ty) where
id_elem : () -> ty
proof_of_left_id : (a : ty) -> ((op a (id_elem ())) = a)
proof_of_right_id : (a : ty) -> ((op (id_elem ())a) = a)
proof_of_associativity : (a, b, c : ty) -> ((op a (op b c)) = (op (op a b) c))
then tried to define groups as
interface (Is_monoid ty op) => Is_group (ty : Type) (op : ty -> ty -> ty) where
inverse : ty -> ty
proof_of_left_inverse : (a : ty) -> (a = (id_elem ()))
but during compilation it showed
When checking type of Group.proof_of_left_inverse:
Can't find implementation for Is_monoid ty op
Is there a way around it.
The error message is a bit misleading, but indeed, the compiler does not know which implementation of Is_monoid to use for your call to id_elem in your definition of proof_of_left_inverse. You can make it work by making it making the call more explicit:
proof_of_left_inverse : (a : ty) -> (a = (id_elem {ty = ty} {op = op} ()))
Now, why is this necessary? If we have a simple interface like
interface Pointed a where
x : a
we can just write a function like
origin : (Pointed b) => b
origin = x
without specifying any type parameters explicitly.
One way to understand this is to look at interfaces and implementations through the lens of other, in a way more basic Idris features. x can be thought of as a function
x : {a : Type} -> {auto p : PointedImpl a} -> a
where PointedImpl is some pseudo type that represents the implementations of Pointed. (Think a record of functions.)
Similarly, origin looks something like
origin : {b : Type} -> {auto j : PointedImpl b} -> b
x notably has two implicit arguments, which the compiler tries to infer during type checking and unification. In the above example, we know that origin has to return a b, so we can unify a with b.
Now i is also auto, so it is not only subject to unification (which does not help here), but in addition, the compiler looks for "surrounding values" that can fill that hole if no explicit one was specified. The first place to look after local variables which we don't have is the parameter list, where we indeed find j.
Thus, our call to origin resolves without us having to explicitly specify any additional arguments.
Your case is more akin to this:
interface Test a b where
x : a
y : b
test : (Test c d) => c
test = x
This will error in the same manner your example did. Going through the same steps as above, we can write
x : {a : Type} -> {b -> Type} -> {auto i : TestImpl a b} -> a
test : {c : Type} -> {d -> Type} -> {auto j : TestImpl c d} -> c
As above, we can unify a and c, but there is nothing that tells us what d is supposed to be. Specifically, we can't unify it with b, and consequently we can't unify TestImpl a b with TestImpl c d and thus we can't use j as value for the auto-parameter i.
Note that I don't claim that this is how things are implemented under the covers. This is just an analogy in a sense, but one that holds up to at least some scrutiny.

Testing if a proof is sound in Idris

I'm trying to write a test code to check if plusComm : (a : Nat) -> (b : Nat) -> a + b = b + a indeed proves a + b = b + a on natural numbers, i.e. the code does not fake one using typed holes, postulate, believe_me, assert_total, etc.
Specifically, if the proof is faked in some way, I want the program to fail in one of the three ways:
Compilation error
Run-time error e.g. segfault
Run-time infinite loop
If these options are not feasible, I'm open to source code analysis as a last resort (for my purposes, that should be written in Idris too). I heard of Language.Reflection but I'm not sure if it's the right tool here.
The code below is one attempt that failed because proofEval doesn't even look at the actual value passed:
plusComm : (a : Nat) -> (b : Nat) -> a + b = b + a
plusComm a b = ?plusComm
proofEval : {a : ty} -> (a = b) -> ty
proofEval {a=a} _ = a
main : IO ()
main = do
putStrLn "Compiled Successfully!"
print (proofEval (plusComm 1 2))
The above, when compiled and run, produces the following output and exits without error.
Compiled Successfully!
3
Partial answer
I found a way to catch postulate and holes using dependent tuples:
plusComm : (a : Nat) -> (b : Nat) -> a + b = b + a
plusComm = plusCommutative
proofEval : (a : Nat) -> (b : Nat) -> (a : Nat ** (b : Nat ** (a + b = b + a)))
proofEval a b = (a ** (b ** plusComm a b))
main : IO ()
main = do
putStrLn "Compiled Successfully!"
print $ fst $ snd $ proofEval 1 2
-- `print $ fst $ proofEval 1 2` doesn't work for the purpose
Output:
Compiled Successfully!
2
Some possible fake proofs and the results:
-- typed hole
plusComm : (a : Nat) -> (b : Nat) -> a + b = b + a
plusComm = ?plusComm
-- result: runtime error (abort)
ABORT: Attempt to evaluate hole Main.plusComm1
-- postulate
postulate plusComm : (a : Nat) -> (b : Nat) -> a + b = b + a
-- result: compilation error
reachable postulates:
Main.plusComm
Note that assert_total or believe_me is not caught using this method as marked in the linked snippet.

Strange error message with Idris interfaces

I'm trying to implement a simple algebraic structures hierarchy using Idris interfaces. The code is as follows:
module AlgebraicStructures
-- definition of some algebraic structures in terms of type classes
%access public export
Associative : {a : Type} -> (a -> a -> a) -> Type
Associative {a} op = (x : a) ->
(y : a) ->
(z : a) ->
(op x (op y z)) = (op (op x y) z)
Identity : {a : Type} -> (a -> a -> a) -> a -> Type
Identity op v = ((x : a) -> (op x v) = x,
(x : a) -> (op v x) = x)
Commutative : {a : Type} -> (a -> a -> a) -> Type
Commutative {a} op = (x : a) ->
(y : a) ->
(op x y) = (op y x)
infixl 4 <**>
interface IsMonoid a where
empty : a
(<**>) : a -> a -> a
assoc : Associative (<**>)
ident : Identity (<**>) empty
interface IsMonoid a => IsCommutativeMonoid a where
comm : Commutative (<**>)
But, Idris is giving this strange error message:
When checking type of constructor of AlgebraicStructures.IsCommutativeMonoid:
Can't find implementation for IsMonoid a
I believe that Idris interfaces works like Haskell's type classes. In Haskell, it should work. Am I doing something silly?
I believe it may be complaining because I don't know that there's anything that constrains the a in the expression Commutative (<**>) - so it doesn't know that you can invoke <**> on that type.
Explicitly specifying the a seems to work for me - Commutative {a} (<**>) - I hope that that means that the a from the interface signature is in scope and available for explicitly passing to other types.

Constraining a function argument in an interface

What is the syntax to constrain a function argument in an interface which takes a function? I tried:
interface Num a => Color (f : a -> Type) where
defs...
But it says the Name a is not bound in interface...
Your interface actually has two parameters: a and f. But f should be enough to pick an implementation:
interface Num a => Color (a : Type) (f : a -> Type) | f where
f here is called a determining parameter.
Here's a nonsensical full example:
import Data.Fin
interface Num a => Color (a : Type) (f : a -> Type) | f where
foo : (x : a) -> f (1 + x)
Color Nat Fin where
foo _ = FZ
x : Fin 6
x = foo {f = Fin} 5

Idris: proof that specific terms are impossible

Idris version: 0.9.16
I am attempting to describe constructions generated from a base value and an iterated step function:
namespace Iterate
data Iterate : (base : a) -> (step : a -> a) -> a -> Type where
IBase : Iterate base step base
IStep : Iterate base step v -> Iterate base step (step v)
Using this I can define Plus, describing constructs from iterated addition of a jump value:
namespace Plus
Plus : (base : Nat) -> (jump : Nat) -> Nat -> Type
Plus base jump = Iterate base (\v => jump + v)
Simple example uses of this:
namespace PlusExamples
Even : Nat -> Type; Even = Plus 0 2
even0 : Even 0; even0 = IBase
even2 : Even 2; even2 = IStep even0
even4 : Even 4; even4 = IStep even2
Odd : Nat -> Type; Odd = Plus 1 2
odd1 : Odd 1; odd1 = IBase
odd3 : Odd 3; odd3 = IStep odd1
Fizz : Nat -> Type; Fizz = Plus 0 3
fizz0 : Fizz 0; fizz0 = IBase
fizz3 : Fizz 3; fizz3 = IStep fizz0
fizz6 : Fizz 6; fizz6 = IStep fizz3
Buzz : Nat -> Type; Buzz = Plus 0 5
buzz0 : Buzz 0; buzz0 = IBase
buzz5 : Buzz 5; buzz5 = IStep buzz0
buzz10 : Buzz 10; buzz10 = IStep buzz5
The following describes that values below the base are impossible:
noLess : (base : Nat) ->
(i : Fin base) ->
Plus base jump (finToNat i) ->
Void
noLess Z FZ m impossible
noLess (S b) FZ IBase impossible
noLess (S b) (FS i) IBase impossible
And the following for values between base and jump + base:
noBetween : (base : Nat) ->
(predJump : Nat) ->
(i : Fin predJump) ->
Plus base (S predJump) (base + S (finToNat i)) ->
Void
noBetween b Z FZ m impossible
noBetween b (S s) FZ IBase impossible
noBetween b (S s) (FS i) IBase impossible
I am having trouble defining the following function:
noJump : (Plus base jump n -> Void) -> Plus base jump (jump + n) -> Void
noJump f m = ?noJump_rhs
That is: if n isn't base plus a natural multiple of jump, then neither is jump + n.
If I ask Idris to case split m it only shows me IBase - then I get stuck.
Would someone point me in the right direction?
Edit 0:
Applying induction to m gives me the following message:
Induction needs an eliminator for Iterate.Iterate.Iterate
Edit 1:
Name updates and here is a copy of the source: http://lpaste.net/125873
I think there's a good reason to get stuck on the IBase case of this proof, which is that the theorem is false! Consider:
noplus532 : Plus 5 3 2 -> Void
noplus532 IBase impossible
noplus532 (IStep _) impossible
plus535 : Plus 5 3 (3 + 2)
plus535 = IBase
To Edit 0: to induct on a type, it needs a special qualifier:
%elim data Iterate = <your definition>
To the main question: sorry that I haven't read through all your code, I only want to make some suggestion for falsifying proofs. From my experience (I even delved the standard library sources to find out some help), when you need to prove Not a (a -> Void), often you can use some Not b (b -> Void) and a way to convert a to b, then just pass it to the second proof. For example, a very simple proof that one list cannot be prefix of another if they have different heads:
%elim data Prefix : List a -> List a -> Type where
pEmpty : Prefix Nil ys
pNext : Prefix xs ys -> Prefix (x :: xs) (x :: ys)
prefixNotCons : Not (x = y) -> Not (Prefix (x :: xs) (y :: ys))
prefixNotCons r (pNext _) = r refl
In your case, I suppose you need to combine several proofs.