I would like to write a function that takes two natural arguments and returns a maybe of a proof of their equality.
I'm trying with
equal : (a: Nat) -> (b: Nat) -> Maybe ((a == b) = True)
equal a b = case (a == b) of
True => Just Refl
False => Nothing
but I get the following error
When checking argument x to constructor Prelude.Maybe.Just:
Type mismatch between
True = True (Type of Refl)
and
Prelude.Nat.Nat implementation of Prelude.Interfaces.Eq, method == a
b =
True (Expected type)
Specifically:
Type mismatch between
True
and
Prelude.Nat.Nat implementation of Prelude.Interfaces.Eq, method == a
b
Which is the correct way to do this?
Moreover, as a bonus question, if I do
equal : (a: Nat) -> (b: Nat) -> Maybe ((a == b) = True)
equal a b = case (a == b) of
True => proof search
False => Nothing
I get
INTERNAL ERROR: Proof done, nothing to run tactic on: Solve
pat {a_504} : Prelude.Nat.Nat. pat {b_505} : Prelude.Nat.Nat. Prelude.Maybe.Nothing (= Prelude.Bool.Bool Prelude.Bool.Bool (Prelude.Interfaces.Prelude.Nat.Nat implementation of Prelude.Interfaces.Eq, method == {a_504} {b_505}) Prelude.Bool.True)
This is probably a bug, or a missing error message.
Please consider reporting at https://github.com/idris-lang/Idris-dev/issues
Is it a known issue or should I report it?
Let's take a look at the implementation of the Eq interface for Nat:
Eq Nat where
Z == Z = True
(S l) == (S r) = l == r
_ == _ = False
You can solve the problem just by following the structure of the (==) function as follows:
total
equal : (a: Nat) -> (b: Nat) -> Maybe ((a == b) = True)
equal Z Z = Just Refl
equal (S l) (S r) = equal l r
equal _ _ = Nothing
You can do it by using with instead of case (dependent pattern matching):
equal : (a: Nat) -> (b: Nat) -> Maybe ((a == b) = True)
equal a b with (a == b)
| True = Just Refl
| False = Nothing
Note that, as Anton points out, this merely a witness on a boolean test result, a weaker claim than proper equality. It might be useful for advancing a proof about if a==b then ..., but it won't allow you to substitute a for b.
Related
I'm trying to build a set datatype.
mutual
data Set : Type -> Type where
Nil : Eq a => Set a
(::) : Eq a => (x : a) -> (s : Set a) -> {auto _ : contains x s = False} -> Set a
contains : Eq a => a -> Set a -> Bool
contains x [] = False
contains x (y :: s) = (x == y) || contains x s
But I have no idea how to deal with this error:
Error: While processing right hand side of contains. Multiple solutions found in search of:
Eq a
test:9:26--9:32
5 | (::) : Eq a => (x : a) -> (s : Set a) -> {auto _ : contains x s = False} -> Set a
6 |
7 | contains : Eq a => a -> Set a -> Bool
8 | contains x [] = False
9 | contains x (y :: s) = (x == y) || contains x s
^^^^^^
Possible correct results:
conArg (implicitly bound at test:9:3--9:49)
conArg (implicitly bound at test:9:3--9:49)
You have multiple instances of Eq a floating around (one for each set element), so Idris isn't sure which one to use. For example, in contains, there's one from contains : Eq a => and another less obvious one from (y :: s). You can disambiguate with
contains : Eq a => a -> Set a -> Bool
contains x [] = False
contains #{eq} x (y :: s) = ((==) #{eq} x y) || contains #{eq} x s
though it may be better to work out some refactor that doesn't have multiple Eq a, if that's possible.
I am working on some exercises on Idris proofs and I keep running into the same problem in various exercises. I first describe the problem in general, and then I give a concrete example:
theorem: (some variables) -> (hypothesis using those variables) -> (proof goal)
Now suppose that I want to give the proof using case-splitting, and that in some cases the assignment of the variables makes the hypothesis false. This means that the situation can never occur, so the proof can continue. But how to tell this to Idris?
For example:
andb_true_elim_2 : (b, c: Bool) -> (b && c = True) -> c = True
andb_true_elim_2 True c prf = prf -- This is OK!
andb_true_elim_2 False c prf = ?hole -- This is the problem
As b is false, b && c = True evaluates to False = True, which is impossible, so there will never be a valid value for prf that reaches this case, so it is irrelevant.
How does one solve these kind of problems?
Thanks!
If you try to pattern match the proof with Refl, Idris will see that the it's impossible. You can then use the impossible keyword to tell Idris to not worry about it.
andb_true_elim_2 : (b, c: Bool) -> (b && c = True) -> c = True
andb_true_elim_2 True c prf = prf
andb_true_elim_2 False c Refl impossible
I'm deconstructing a list into head and tail but later I need a proof that they give me the original list back when combined:
test: Bool -> String
test b = let lst = the (List Nat) ?getListFromOtherFunction in
case lst of
Nil => ""
x :: xs =>
let eq = the ((x::xs) = lst) ?howToDoIt in ""
I'm using Idris 1.3.1.
You can do it with dependent pattern matching:
test: List Nat -> String
test lst with (lst) proof prf
| Nil = ""
| (x :: xs) = ?something
Here prf will hold your equality.
However, I think it's better to simply match on lst in the LHS, then your proofs will auto-simplify where needed.
I want a find function for Streams of size-bounded types which is analogous to the find functions for Lists and Vects.
total
find : MaxBound a => (a -> Bool) -> Stream a -> Maybe a
The challenge is it to make it:
be total
consume no more than constant log_2 N space where N is the number of bits required to encode the largest a.
take no longer than a minute to check at compile time
impose no runtime cost
Generally a total find implementation for Streams sounds absurd. Streams are infinite and a predicate of const False would make the search go on forever. A nice way to handle this general case is the infinite fuel technique.
data Fuel = Dry | More (Lazy Fuel)
partial
forever : Fuel
forever = More forever
total
find : Fuel -> (a -> Bool) -> Stream a -> Maybe a
find Dry _ _ = Nothing
find (More fuel) f (value :: xs) = if f value
then Just value
else find fuel f xs
That works well for my use case, but I wonder if in certain specialized cases the totality checker could be convinced without using forever. Otherwise, somebody may suffer a boring life waiting for find forever ?predicateWhichHappensToAlwaysReturnFalse (iterate S Z) to finish.
Consider the special case where a is Bits32.
find32 : (Bits32 -> Bool) -> Stream Bits32 -> Maybe Bits32
find32 f (value :: xs) = if f value then Just value else find32 f xs
Two problems: it's not total and it can't possibly return Nothing even though there's a finite number of Bits32 inhabitants to try. Maybe I could use take (pow 2 32) to build a List and then use List's find...uh, wait...the list alone would take up GBs of space.
In principle it doesn't seem like this should be difficult. There's finitely many inhabitants to try, and a modern computer can iterate through all 32-bit permutations in seconds. Is there a way to have the totality checker verify the (Stream Bits32) $ iterate (+1) 0 eventually cycles back to 0 and once it does assert that all the elements have been tried since (+1) is pure?
Here's a start, although I'm unsure how to fill the holes and specialize find enough to make it total. Maybe an interface would help?
total
IsCyclic : (init : a) -> (succ : a -> a) -> Type
data FinStream : Type -> Type where
MkFinStream : (init : a) ->
(succ : a -> a) ->
{prf : IsCyclic init succ} ->
FinStream a
partial
find : Eq a => (a -> Bool) -> FinStream a -> Maybe a
find pred (MkFinStream {prf} init succ) = if pred init
then Just init
else find' (succ init)
where
partial
find' : a -> Maybe a
find' x = if x == init
then Nothing
else
if pred x
then Just x
else find' (succ x)
total
all32bits : FinStream Bits32
all32bits = MkFinStream 0 (+1) {prf=?prf}
Is there a way to tell the totality checker to use infinite fuel verifying a search over a particular stream is total?
Let's define what it means for a sequence to be cyclic:
%default total
iter : (n : Nat) -> (a -> a) -> (a -> a)
iter Z f = id
iter (S k) f = f . iter k f
isCyclic : (init : a) -> (next : a -> a) -> Type
isCyclic init next = DPair (Nat, Nat) $ \(m, n) => (m `LT` n, iter m next init = iter n next init)
The above means that we have a situation which can be depicted as follows:
-- x0 -> x1 -> ... -> xm -> ... -> x(n-1) --
-- ^ |
-- |---------------------
where m is strictly less than n (but m can be equal to zero). n is some number of steps after which we get an element of the sequence we previously encountered.
data FinStream : Type -> Type where
MkFinStream : (init : a) ->
(next : a -> a) ->
{prf : isCyclic init next} ->
FinStream a
Next, let's define a helper function, which uses an upper bound called fuel to break out from the loop:
findLimited : (p : a -> Bool) -> (next : a -> a) -> (init : a) -> (fuel : Nat) -> Maybe a
findLimited p next x Z = Nothing
findLimited p next x (S k) = if p x then Just x
else findLimited pred next (next x) k
Now find can be defined like so:
find : (a -> Bool) -> FinStream a -> Maybe a
find p (MkFinStream init next {prf = ((_,n) ** _)}) =
findLimited p next init n
Here are some tests:
-- I don't have patience to wait until all32bits typechecks
all8bits : FinStream Bits8
all8bits = MkFinStream 0 (+1) {prf=((0, 256) ** (LTESucc LTEZero, Refl))}
exampleNothing : Maybe Bits8
exampleNothing = find (const False) all8bits -- Nothing
exampleChosenByFairDiceRoll : Maybe Bits8
exampleChosenByFairDiceRoll = find ((==) 4) all8bits -- Just 4
exampleLast : Maybe Bits8
exampleLast = find ((==) 255) all8bits -- Just 255
I have the following code:
doSomething : (s : String) -> (not (s == "") = True) -> String
doSomething s = ?doSomething
validate : String -> String
validate s = case (not (s == "")) of
False => s
True => doSomething s
After checking the input is not empty I would like to pass it to a function which accepts only validated input (not empty Strings).
As far as I understand the validation is taking place during runtime
but the types are calculated during compile time - thats way it doesn't work. Is there any workaround?
Also while playing with the code I noticed:
:t (("la" == "") == True)
"la" == "" == True : Bool
But
:t (("la" == "") = True)
"la" == "" = True : Type
Why the types are different?
This isn't about runtime vs. compile-time, since you are writing two branches in validate that take care, statically, of both the empty and the non-empty input cases; at runtime you merely choose between the two.
Your problem is Boolean blindness: if you have a value of type Bool, it is just that, a single bit that could have gone either way. This is what == gives you.
= on the other hand is for propositional equality: the only constructor of the type(-as-proposition) a = b is Refl : a = a, so by pattern-matching on a value of type a = b, you learn that a and b are truly equal.
I was able to get your example working by passing the non-equality as a proposition to doSomething:
doSomething : (s : String) -> Not (s = "") -> String
doSomething "" wtf = void $ wtf Refl
doSomething s nonEmpty = ?doSomething
validate : String -> String
validate "" = ""
validate s = doSomething s nonEmpty
where
nonEmpty : Not (s = "")
nonEmpty Refl impossible
As far as I understand the validation is taking place during runtime
but the types are calculated during compile time - thats way it
doesn't work.
That's not correct. It doesn't work because
We need the with form to perform dependent pattern matching, i. e. perform substitution and refinement on the context based on information gained from specific data constructors.
Even if we use with here, not (s == "") isn't anywhere in the context when we do the pattern match, therefore there's nothing to rewrite (in the context), and we can't demonstrate the not (s == "") = True equality later when we'd like to call doSomething.
We can use a wrapper data type here that lets us save a proof that a specific pattern equals the original expression we matched on:
doSomething : (s : String) -> (not (s == "") = True) -> String
doSomething s = ?doSomething
data Inspect : a -> Type where
Match : {A : Type} -> {x : A} -> (y : A) -> x = y -> Inspect x
inspect : {A : Type} -> (x : A) -> Inspect x
inspect x = Match x Refl
validate : String -> String
validate s with (inspect (not (s == "")))
| Match True p = doSomething s p
| Match False p = s