I am trying to write a function in Isabelle for some tasks in an assignment
and I wanted to make sure that my function works correctly so I thought about
testing it in SML but I can't seem to be able to figure out how to write it. I
have never used/wrote/learned functional programming so I am having a little trouble
with it. Can someone help me or maybe if there is something in Isabelle about testing
how a function works can he point me to the correct direction?
The functions are the following and basically are removing the first occurrence of an
element in a list and removing all occurrences from a list
fun del1:: "'a ⇒ 'a list ⇒ 'a list" where
"del1 a Nil = Nil" |
"del1 a (x#xs) = (if x = a then xs else x#(del1 a xs))"
fun delall:: "'a ⇒ 'a list ⇒ 'a list" where
"delall a Nil = Nil" |
"delall a (x#xs) = (if x = a then (delall a xs) else x#(delall a xs))"
I am not quite sure whether I get your question. First, the syntax of Isabelle/HOL and SML is not very different. If you just want to get variants of your function in SML, probably the fastest way is using Isabelle's code generator
export_code del1 delall in SML
which results in something like
fun del1 A_ a [] = []
| del1 A_ a (x :: xs) = (if HOL.eq A_ x a then xs else x :: del1 A_ a xs);
fun delall A_ a [] = []
| delall A_ a (x :: xs) =
(if HOL.eq A_ x a then delall A_ a xs else x :: delall A_ a xs);
However, since this contains some Isabelle specific stuff (like a dictionary construction to get rid of type classes) maybe you prefer hand-written code:
fun del1 a [] = []
| del1 a (x::xs) = if x = a then xs else x :: (del1 a xs)
fun delall a [] = []
| delall a (x::xs) = if x = a then delall a xs else x :: delall a xs
On the other hand, if you just want to try out your functions on some inputs, you can do that inside Isabelle using value. E.g.,
value "del1 (2::nat) [1, 2 , 3]"
value "delall ''x'' [''x'', ''y'', ''z'', ''q'', ''x'']"
There is little to add to the answer by Chris, only this detail: In Isabelle2013-2 the Isabelle/jEdit Documentation panel has a few quickstart examples. This includes src/HOL/ex/ML.thy which shows a little bit of Isabelle/HOL as logical language and SML as functional language, and some connections between them.
Related
For example, I would like to define a function that extracts the first element of a list. For this function, I do not care about the case when the list is empty (e.g. I can make sure that every time I use the function, I will pass a non-empty list). But Isabelle would warn that
Missing patterns in function definition:
extracts [] = undefined
How can I deal with situations like this?
You have quite a few options available, for example:
fun extracts where "extracts xs = hd xs"
definition extracts where [simp]: "extracts = hd"
fun extracts where "extracts xs = (case xs of (x # _) ⇒ x)"
fun extracts where "extracts (x # _) = x" | "extracts [] = undefined"
For a uni project I'm working on a proof with Iabelle/HOL 2018. I'm getting an error when applying obvious results. However, this error is not stating anything about what is going wrong.
At first I thought it was an unification problem. But when I simplified it turned out to be a behavior I totally don't understand.
I have a minimal example which is as follows:
I define proposition formulas as type1 and then I have a tail-recursive function that simply collects each sub formula. There are probably better ways to do that. I just tried to replicate the error in the easiest way possible. Then I want to show a simple equality (I have proven that in my code, here I just simplify by "sorry") and then I want to use that fact in some other proof, however it doesn't seem to apply the proven fact, even though I added it to the simp set. Even, directly applying it doesn't work for me.
Here is the Code:
theory test
imports Main
begin
datatype 'a type1 =
Bot
| Atm 'a
| Neg "'a type1"
| Imp "'a type1" "'a type1"
fun func :: "'a type1 ⇒ ('a type1) list list ⇒ ('a type1) list list"
where
"func Bot acc = acc"
| "func (Atm p) acc = acc"
| "func (Neg p) acc = func p ([Neg p] # acc)"
| "func (Imp p q) acc = func q (func p ([Imp p q] # acc))"
lemma lemma1 [simp]:
"func p acc = func p [] # acc"
sorry
lemma lemma2:
"func p acc = func p acc"
proof -
have "func p acc = func p [] # acc" by auto
show ?thesis sorry
qed
end
In my opinion this should be no problem. However, in the first line of the proof of lemma2 I get an error. But there is no explanation to the error such as "failed to finish proof" or anything similar.
Does anyone know what I'm doing wrong? Or did anyone have similar problems or behavior?
Quoting from the book 'A Proof Assistant for Higher-Order Logic': "In its most basic form, simplification means the repeated application of equations from left to right ... Only equations that really simplify, like rev (rev xs) = xs and xs # [] = xs, should be declared as default simplification rules." (there are other valuable resources that explain this issue, e.g. the official Isabelle/Isar reference manual or the textbook 'Concrete Semantics with Isabelle/HOL'). Therefore, lemma1 is not a good choice for a default simplification rule and adding it to the simpset can lead to nontermination, as your example demonstrates.
If you would like to use lemma1 in another proof, perhaps, you can use something similar to
have "func p acc = func p [] # acc by (rule lemma1)"
or merely rewrite the simp rule as
func p [] # acc = func p acc.
However, in general, you need to be very careful when introducing new simp rules, especially in the global theory context.
In OCaml, a typical fold function looks like this:
let rec fold (combine: 'a -> 'b -> 'b) (base: 'b) (l: 'a list) : 'b =
begin match l with
| [] -> base
| x :: xs -> combine x (fold combine base xs)
end
For those familiar with OCaml (unlike me), it should be pretty straightforward what it's doing.
I'm writing a function that returns true when all items in the list satisfy the condition: if condition x is true for all x in some list l. However I'm implementing the function using a fold function and I'm stuck. Specifically I don't know what the list should return. I know that ideally the condition should be applied to every item in the list but I have no idea how the syntax should look. x && acc works but it fails a very simply test (shown below)
let test () : bool =
not (for_all (fun x -> x > 0) [1; 2; -5; -33; 2])
;; run_test "for_all: multiple elements; returns false" test
Here is my preliminary attempt. Any help is appreciated:
let for_all (pred: 'a -> bool) (l: 'a list) : bool =
fold (fun(x:'a)(acc: bool)-> _?_&&_?_ )false l
let rec fold (combine: 'a -> 'b -> 'b) (base: 'b) (l: 'a list) : 'b =
match l with
| [] -> base
| x::xs -> combine x (fold combine base xs)
let for_all (pred: 'a -> bool) (lst: 'a list) =
let combine x accum =
(pred x) && accum
in
fold combine true lst
Your combine function should not do x && base because elements of the list are not usually bool. You want your predicate function first evaluate the element to bool, then you "and" it with the accumulator.
There is no need for begin and end in fold. You can just pattern match with match <identifier> with.
There are two widespread types of fold: fold_left and fold_right. You're are using fold_right, which, basically, goes through the whole list and begins "combining" from the end of the list to the front. This is not tail-recursive.
fold_left, on the other hand goes from the front of the list and combines every element with the accumulator right away. This does not "eat up" your stack by a number of recursive function calls.
Basically the function will take one parameter as a character, number and check whether it is inside the List or not ?
let rec (member: a -> List a -> Bool) x =
| [] -> False
| Cons y ys -> if x == y then True else member x ys
;;
I got the solution but it seems too vague.
Could anyone show me how to use Cons operator in this particular case ?
Thanks
In Ocaml, the cons operator is ::. But it is not the only problem of your piece of code.
Here your function takes only one argument (x) but you use it with two (member x ys), you wanted to do let rec member x l = match l with or let rec member x = function which is equivalent.
In OCaml you don't have to give the type of your values, but if you do, this is not the rigth syntax. OCaml types are not capitalized, type parameters start with '
and are placed before the type they parameterize, then the type of your function is 'a -> 'a list -> bool. Moreover, for a function you have to give the type of the parameters and the return type separately (let rec member (x : 'a) (l : 'a list) : bool =).
The operator for equality is = and not ==.
Even if it is correct, don't use if then else to return a boolean, logical operators || and && should be used instead.
Corrected code:
let rec member x = function
| [] -> false
| y :: ys -> x = y || member x ys
I want to match and remove those elements in l :: 'a list that match the predicate P :: ('a => bool)
What is the best way to accomplish such a task? How can I find out about existing functions that might help me?
One way to find functions you expect to exist is the document What's in Main from the Isabelle documentation. It gives a quick overview of the main types, functions and syntax provided by the theory Main of Isabelle/HOL.
If you look at the List section in ths document, you find the function filter which seems to have the correct type.
Short Story: Use find_consts
Long Story:
This a How-To to conquer such problems.
In Main, there is List.dropWhile
List.dropWhile :: "('a => bool) => 'a list => 'a list"
However, it only removes from the beginning. This may not be the intended function.
value "List.dropWhile (λ x. x = ''c'') [''c'', ''c'', ''d'']"
"[''d'']"
value "List.dropWhile (λ x. x = ''c'') [''d'', ''c'', ''c'']"
"[''d'', ''c'', ''c'']"
Manual Approach
We can write a function ourselves which removes all occurrences
fun dropAll :: "('a => bool) => 'a list => 'a list" where
"dropAll P [] = []"
| "dropAll P (x # xs) = (if P x then dropAll P xs else x # (dropAll P xs))"
Searching the Library
However, this function is equivalent to filtering with ¬ P
How can we find such library functions?
If we know the signature of what we want to do, we can use find_consts
find_consts "('a ⇒ bool) ⇒ 'a list ⇒ 'a list"
It returns 3 functions from Main, with that signature: List.dropWhile, List.filter, List.takeWhile
Now, let's show that we don't need dropAll but can do the same with filter.
lemma "dropAll P l = filter (λ x. ¬ P x) l"
apply(induction l)
by simp_all
It is advisable not to implement things like dropAllyourself but rather use filter. Thus, all lemmata proven for filter are usable.
Hints
Hint: we can use the convenient list comprehension syntax to write e.g. filter expressions
lemma "filter (λ x. ¬ P x) l = [x ← l. ¬ P x]" by simp