View Proof Steps From Tactic Application - sml

I have spent some time constructing "forward proofs" using the theorem library in HOL. I am now hoping to move to applying tactics to make "backward proofs".
I am wondering if there is a way to, after a tactic has been applied, to view the list of theorems that the tactic applied, i.e., to reconstruct the forward proof in detail. This is mostly to help me understand how tactices work.
For example:
> g `x = 5 ==> 2*x = 10`;
val it = ...
> e (rw[]);
OK...
.
.
.
|- x = 5 ==> 2 * x = 10: proof
>
>
> list_steps(); (* or something similar? *)
REWRITE_RULE [...] t1
REWRITE_RULE [MULT] t2
REWRITE_RULE [MULT_ZERO] t3...
etc.
Thank you!

Related

OCaml Factorial Function with Restrictions

I'm trying to learn OCaml on my own, and I've reached imperative programming. I found this little exercise that I'm just completely stuck on how to even approach. It seems so simple, but I think my understanding is just lacking.
The problem asks me to write the function for factorial without using the rec keyword, and without loops. It's supposed to teach me the environment model, but that's also confusing to me.
My first thought was to try something like this:
let factorial =
let f = ref (fun n -> 0) in
let temp_factorial n =
if n = 0
then 1
else
begin
f := n * !f*(n-1)
!f
end
But I'm not sure if this works. Any help would be greatly appreciated :)
Your code is a little strange and wrong, but the basic idea is workable. Once you have a reference f to a function of type int -> int, you can use !f freely in later code. In fact you can assign f so it refers to a function that uses !f. This is equivalent to recursion, but it uses the imperative part of OCaml.
let f = ref (fun n -> n + 1)
f :=
(fun n ->
if n < 2 then 1
else (* ... left as an exercise ... *)
)
let factoral n = !f n
The key is that the part left as an exercise can use !f.

How does the "in" instruction nesting works?

I'm struggling to understand the way that the "in" instruction works, I have an exam in a few days and even though I fell pretty confident with the way ocaml works, there's a lot of previous exams that brings me to some scoping questions, as far as I know ocaml is a static scope language, so if for example you declare a value and you use it inside a function (without passing it as an argument of course), even if you overwrite the value the function will still use the previous one, for example
let a = 5;;
let f x = a+x;;
let a = 1;;
f 1;;
Will return 6 even though the a value has been overwritten, but there are some pretty sketchy questions in the exam, like for example
let a = 6 in
let b x = a + x in
let a = 42 in
b a;;
This one confuses me a lot, how does the "in" work? I know that this returns 48, but I'm struggling to see a pattern that I can use to understand how the scoping works when you use the "in" instruction.
Any explanation will be appreciated really much
Thanks in advance :D
Will return 6 even though the a value has been overwritten
It's not overwritten. You create a new variable with the same name. I.e., you don't change the existing variable - you create a new one which hides the existing one. What happens is this:
let a1 = 5;;
let f x = a1 + x;;
let a2 = 1;;
f 1;;
The same in the second example:
let a1 = 6 in
let b x = a1 + x in
let a2 = 42 in
b a2;;

Can I unpack an F# list with no warnings?

F# makes it easy to unpack tuples. Unpacking lists is also feasible, but the compiler issues a warning:
let m = [1; 2; 3]
let [a; b; c] = m
// Incomplete pattern matches on this expression. For example, the value '[_;_;_;_]' may indicate a case not covered by the pattern(s)
Is there a way to avoid this warning?
You can disable warnings per file by using the #nowarn directive (in your case #nowarn "25") or you can disable warnings on the command line with --nowarn.
Check out the F# Compiler Directives for details.
There is currently no way to re-enable warnings again, when first disabled.
Your match may (unexpectedly) result in a runtime error if the number of elements cannot be unpacked to [a;b;c], so instead you can use a complete match that is explicit about the risc:
let m = [1;2;3]
let (a,b,c) =
match m with
| [a;b;c] -> (a,b,c)
| _ -> failwith "Expected exactly three items in m"
What would happen if your list m has 2 or 4 elements?
There is obviously a way, plain old pattern matching:
let a, b, c =
match m with
| [a;b;c] -> a,b,c
| _ -> ... // handle the length!=3 case
F# allows you to deconstruct the right-hand side objects that way when there's clear that you only have a single case you need to cover. This is the case with tuples, since there's only one tuple type that would match both the left and the right hand side. Something like this obviously would not compile, because the types won't match:
let m = 1, 2
let a, b, c = m
Yet in your case there's no guarantee that you're not in fact in this scenario:
let m = [ 1; 2 ]
let [1;2;3] = m
You're in fact asking the compiler to allow non-exhaustive pattern matching. You can disable the warning as noted in the other answer, but you're inviting runtime errors that way.
One obvious, but hardly elegant, way is:
let m = [1; 2; 3]
let a = List.item 0 m
let b = List.item 1 m
let c = List.item 2 m
You can write a helper function to make it neater:
let unpack3 x = (List.item 0 x, List.item 1 x, List.item 2 x)
let (a, b, c) = unpack3 m
Basically a list is not a great fit if you know you are always going to have a fixed number of items.

Evaluating List to Weak Head Normal Form

Given the following list from 1 to 100:
> let x = [1..100]
I run sprint x to observe its unevaluated value.
> :sprint x
x = _
Then, I ran seq to evaluate it to Weak Head Normal Form:
> seq x ()
()
But re-running sprint x shows (what I think) is the same value.
> :sprint x
x = _
Why is that?
I think this bheklilr's comment should be marked as the answer:
What is the type of x? If it's (Num a, Enum a) => [a] then this won't work as expected. Try let x = [1..100] :: [Int]. In reality, when you print x with the more general type GHCi specializes it to Integer to do the printing. This means that the values you see printed are not actually stored back in x's thunk. Using a concrete type avoids this problem.
With the additional note from David Young that this problem won't occur on GHCi versions earlier than 7.8, when the monomorphism restriction was enabled.

Re-organizing a list in prolog

I am trying to write some Prolog code to take a list such as:
[[park, joe], [park, bob], [park, kate], [school, joe], [zoo, amy], [zoo, ted]].
and organizes the list into the form:
[[park,[joe, bob, kate]], [school,[joe]], [zoo,[amy, ted]]].
It can be assumed that all matching heads of each element (park = park, zoo = zoo) are directly next to each other in the list because the code I made to create the list sorts it in alphabetical order. I can't seem to figure out how to accomplish this and seem to get errors at every turn :(. Below is the code that I have so far in the last state that it ran without errors and I will try to explain what I was thinking.
merge([],[]).
merge([First|Rest], Z) :-
merge(Rest, U),
[Meet1, Person1] = First,
( =(U, []) -> % beginning case from recursion, U is empty
Meet2 = [],
Person2 = [];
[[Meet2|Person2]|_] = U),
( =(Meet1, Meet2) -> % Case of matching heads, combine the tails
print('Match '),
append([First], U, Z);
print('No-match '), % otherwise, not matching
append([First], U, Z) ).
So what I was trying to do is use appends to add all of the changes to U and return it to the console with Z. such as,
( =(Meet1, Meet2) ->
append(Person1, Person2, Combpersons),
append([Meet1], [Combpersons], T),
append(T, U, Z);
...no match code here..).
However my code keeps ending prematurely with a false when I try to change or add appends like this in the first block of code I put here. Even a change such as turning append([First], U, Z) into append([Meet1], U, Z) makes my code end with a false and I am not understanding why. Any help/hints on creating a solution would be appreciated.
I think that learning any language it's a process where low and high level issues must be interleaved. So far, you're learning the basic syntax. But why you use such unreadable constructs ? And of course, any programming language builds upon a set of patterns, usually covered by libraries. Consider
l2p([A,B],A-B).
?- maplist(l2p,[[park, joe], [park, bob], [park, kate], [school, joe], [zoo, amy], [zoo, ted]], L),group_pairs_by_key(L,G).
L = [park-joe, park-bob, park-kate, school-joe, zoo-amy, zoo-ted],
G = [park-[joe, bob, kate], school-[joe], zoo-[amy, ted]].
Anyway, here is your code restructured:
merge([],[]).
merge([[Meet, Person]|Rest], Z) :-
merge(Rest, U),
( U = []
-> % beginning case from recursion, U is empty
Z = [[Meet, [Person]]]
; U = [[Meet, Persons] | Rest1]
-> % Case of matching heads, combine the tails
Z = [[Meet, [Person | Persons]] | Rest1]
; % otherwise, not matching
Z = [[Meet, [Person]] | U]
).
If you had your initial list as a list of pairs instead, you could use library(pairs), available in SWI-Prolog.
?- group_pairs_by_key([park-joe, park-bob, park-kate, school-joe, zoo-amy, zoo-ted], G).
G = [park-[joe, bob, kate], school-[joe], zoo-[amy, ted]].
Using the library gives you more than just this "reorganization". There is also library(ugraphs), which might be better suited, depending on what you are doing.
Your code fails, because you are trying to extract the place and the person before checking if there are any.
No use for append here, the reordering looks pretty complicated, but I did my best with the variable names. Furthermore you'll only need one ->: If you hadn't found a tuple with the same first coordinate, you'll want a to start a new, it doesn't matter if there was none before.
merge([],[]).
merge([[Place,Person]|Rest], [[Place,Group]|OtherGroups]) :-
merge(Rest, U),
(U = [[Place,Others]|OtherGroups] ->
Group = [Person|Others];
[OtherGroups,Group] = [U, [Person]]).
Edit: I changed the solution for readablity reasons.