2024-04-30 11:44:28 +02:00
open Parser_entry
2024-04-09 11:30:52 +02:00
open Affichage
2024-04-30 11:44:28 +02:00
open Proof
open Types
2024-05-16 12:38:45 +02:00
open Hlam
2024-05-17 21:28:02 +02:00
open Lam
2024-04-09 11:09:33 +02:00
2024-04-16 11:40:08 +02:00
type entry =
2024-05-17 14:14:28 +02:00
Simple of ( unit -> instr )
2024-04-25 04:20:12 +02:00
| Reduce of Lam . lam
2024-04-16 11:40:08 +02:00
| AlphaEquiv of Lam . lam * Lam . lam
2024-05-13 18:05:28 +02:00
type interactive_state = ( hlam * ty ) option * proof
2024-04-16 11:40:08 +02:00
2024-05-17 21:28:02 +02:00
module StringMap = Map . Make ( String )
2024-04-30 11:44:28 +02:00
let parse_lam t =
match Parser . main Lexer . token t with
| Lam l -> l
2024-05-17 14:14:28 +02:00
| Instr _ -> failwith " entry must be a lam "
2024-04-30 11:44:28 +02:00
let parse_cmd t =
match Parser . main Lexer . token t with
2024-05-17 14:14:28 +02:00
| Instr is -> is
2024-04-30 11:44:28 +02:00
| Lam _ -> failwith " entry must be a cmd "
2024-05-13 18:05:28 +02:00
let show_beta_reduction e =
2024-04-25 04:20:12 +02:00
let rec aux = function
Some e ->
print_expr e ;
print_newline () ;
aux ( Lam . betastep e ) ;
| None -> ()
in print_expr e ;
print_newline () ;
2024-04-25 04:33:42 +02:00
let e = Lam . alpha_convert ~ readable : true e in
2024-04-25 04:20:12 +02:00
print_expr e ;
print_newline () ;
aux ( Lam . betastep e )
2024-05-13 18:05:28 +02:00
let rec beta_reduce ( l : Lam . lam ) =
match Lam . betastep l with
| None -> l
| Some l' -> beta_reduce l'
let clean_state ( ( s , p ) : interactive_state ) =
let assoc , new_p = clean_proof p in
match s with
| None -> None , new_p
| Some ( hl , ty ) -> Some ( clean_hlam assoc hl , ty ) , new_p
2024-04-25 04:20:12 +02:00
let alpha_get_lam where_from =
let input_str = In_channel . input_all where_from in
match Str . split ( Str . regexp " & " ) input_str with
[ s1 ; s2 ] -> AlphaEquiv (
2024-04-30 11:44:28 +02:00
parse_lam ( Lexing . from_string ( s1 ^ " \n " ) ) ,
parse_lam ( Lexing . from_string s2 )
2024-04-25 04:20:12 +02:00
)
| _ -> failwith " Alpha-equivalence: nombre de delimiteurs incorrect "
2024-05-17 21:28:02 +02:00
let check_via_coq ( e : lam ) ( t : ty ) : unit =
(* fill a map to track all types used in the proof *)
let rec fill_ty_map ( m : int StringMap . t ) = function
TVar x -> StringMap . add x 0 m
| Arr ( t1 , t2 ) | Or ( t1 , t2 ) | And ( t1 , t2 ) ->
let m1 = fill_ty_map m t1 in
fill_ty_map m1 t2
| Bot -> m
(* generate the "forall A B.." *)
in let intro_of_ty ( m : int StringMap . t ) : string * int =
let tys = StringMap . to_list m in
let n = List . length tys in
let s = List . fold_left ( fun acc x -> ( fst x ^ " " ) ^ acc ) " " tys in
if n = 0
then ( " " , 0 )
else ( " forall " ^ s ^ " , " , n )
(* generate the right amount of intro. to introduce type variables *)
in let rec repeat_intro n =
if n = 0
then " "
else " intro. " ^ repeat_intro ( n - 1 )
in
let m = fill_ty_map StringMap . empty t in
let ( ty_vars , intro_n ) = intro_of_ty m in
let goal_ty = string_of_ty t in
let proof_term = " ( " ^ string_of_expr e ^ " ) " in
let checker_file = open_out " checker.v " in
let _ =
Printf . fprintf checker_file " Goal %s%s. \n %s \n exact %s. \n "
ty_vars goal_ty ( repeat_intro intro_n ) proof_term ;
close_out checker_file in
(* start Coq in interactive mode and send it the proof term
while blocking coqtop to print on stdout * )
let r = Unix . system " coqtop < checker.v > log 2>&1 " in
match r with
Unix . WEXITED x ->
if x = 0
then print_error " Validated by Coq. " " "
else print_error " Couldn't not validate proof. " " "
| _ -> print_error " Coq failed. " " "
2024-05-13 18:05:28 +02:00
(* * Interactive loop
- cg : current top goal : type and reference to lambda - term
- g , gs : next goals
- sq : previous states of the interactive loop
* )
2024-05-17 14:14:28 +02:00
let rec interactive ( get_instr : unit -> instr ) ( sl : ( interactive_state ) list ) : proof =
2024-05-14 10:49:24 +02:00
let ( cg , ( g , gs ) ) , sq = match sl with
[] -> ( None , ( None , [] ) ) , []
| s :: sq -> s , sq
in
2024-04-30 11:44:28 +02:00
begin
let _ = match g with
2024-05-01 11:07:40 +02:00
None -> print_string " \n \027 [1mNo more goals. \027 [0m \n "
2024-05-01 10:44:36 +02:00
| Some g' -> print_newline () ; print_goal g'
2024-04-30 11:44:28 +02:00
in
2024-05-01 10:35:12 +02:00
try
2024-05-17 14:14:28 +02:00
match get_instr () with
Cmd c -> begin match c with
Goal ty ->
let rh = Ref ( ref Hole ) in
[ Some ( rh , ty ) , ( Some ( rh , ty , [] ) , [] ) ] | > interactive get_instr
| Undo -> interactive get_instr sq
| Qed -> begin match cg with
None ->
print_error " No current goal " " " ;
( cg , ( g , gs ) ) :: sq | > interactive get_instr
| Some ( h , t ) ->
let l = lam_of_hlam h
| > beta_reduce in
if Typing . typecheck [] l t then begin
print_string " Ok " ;
2024-05-17 21:28:02 +02:00
( cg , ( g , gs ) ) :: sq | > interactive get_instr
2024-05-17 14:14:28 +02:00
end else begin
print_error " Typing failed " " " ;
print_expr l ;
print_newline () ;
print_ty t ;
( cg , ( g , gs ) ) :: sq | > interactive get_instr
end
end
2024-05-17 21:28:02 +02:00
| Check -> begin match cg with
None ->
print_error " No current goal " " " ;
( cg , ( g , gs ) ) :: sq | > interactive get_instr
| Some ( h , t ) ->
begin try
let l = lam_of_hlam h in
check_via_coq l t
with _ -> print_error " Proof is not over " " " ;
end ;
( cg , ( g , gs ) ) :: sq | > interactive get_instr ;
end
2024-05-13 18:05:28 +02:00
end
| Tact t ->
2024-05-17 14:14:28 +02:00
( cg , ( apply_tactic ( g , gs ) t ) ) :: ( clean_state ( cg , ( g , gs ) ) ) :: sq | > interactive get_instr
2024-05-01 10:35:12 +02:00
with
Parser . Error ->
2024-05-01 11:07:40 +02:00
print_error " Invalid input " " " ;
2024-05-17 14:14:28 +02:00
( cg , ( g , gs ) ) :: sq | > interactive get_instr
2024-05-11 11:44:43 +02:00
| TacticFailed arg ->
print_error " Tactic failed " arg ;
2024-05-17 14:14:28 +02:00
( cg , ( g , gs ) ) :: sq | > interactive get_instr
2024-05-14 11:43:57 +02:00
| End_of_file | Lexer . Eof ->
2024-05-01 10:35:12 +02:00
print_string " Bye! \n " ;
( g , gs )
2024-04-30 11:44:28 +02:00
end
2024-04-16 11:40:08 +02:00
let nom_fichier = ref " "
2024-04-25 04:20:12 +02:00
let reduce = ref false
2024-04-16 14:24:06 +02:00
let alpha = ref false
2024-04-25 04:20:12 +02:00
let equiv_fichier = ref " "
2024-04-16 11:40:08 +02:00
let recupere_entree () =
let optlist = [
2024-04-25 04:20:12 +02:00
( " -alpha " ,
Arg . Set alpha ,
" Vérifie l'alpha équivalence de deux termes séparés par & " ) ;
( " -reduce " ,
Arg . Set reduce ,
" Affiche les réductions successives du lambda-terme " )
2024-04-16 11:40:08 +02:00
] in
let usage = " Bienvenue à bord. " in (* message d'accueil, option -help *)
Arg . parse (* ci-dessous les 3 arguments de Arg.parse : *)
optlist (* la liste des options definie plus haut *)
( fun s -> nom_fichier := s ) (* la fonction a declencher lorsqu'on recupere un string qui n'est pas une option : ici c'est le nom du fichier, et on stocke cette information dans la reference nom_fichier *)
usage ; (* le message d'accueil *)
2024-04-16 14:24:06 +02:00
try
2024-04-16 11:40:08 +02:00
let where_from = match ! nom_fichier with
| " " -> stdin
| s -> open_in s in
2024-04-25 04:20:12 +02:00
if ! alpha
then alpha_get_lam where_from
else if ! reduce
2024-05-14 11:43:57 +02:00
then Reduce ( Lexing . from_channel where_from | > parse_lam )
else Simple begin
let cmd_buff = ref [] in
if ! nom_fichier = " " then
(
fun () ->
match ! cmd_buff with
| [] ->
begin match ( read_line () ) ^ " \n "
| > Lexing . from_string
| > parse_cmd with
[] -> raise Parser . Error
| e :: q -> cmd_buff := q ; e
end
| e :: q -> cmd_buff := q ; e
)
else
(
fun () ->
match ! cmd_buff with
| [] ->
begin match ( input_line where_from ) ^ " \n "
| > Lexing . from_string
| > parse_cmd with
[] -> raise End_of_file
| e :: q -> cmd_buff := q ; e
end
| e :: q -> cmd_buff := q ; e
)
end
2024-05-01 11:07:40 +02:00
with e -> ( print_error " problème de saisie " " " ; raise e )
2024-04-09 11:09:33 +02:00
2024-04-16 11:40:08 +02:00
(* la fonction principale *)
let run () =
try
match recupere_entree () with
2024-05-17 14:14:28 +02:00
Simple get_instr ->
let _ = interactive get_instr [ None , ( None , [] ) ] in ()
2024-05-14 11:43:57 +02:00
| Reduce l ->
let _ = show_beta_reduction l in ()
2024-04-16 11:40:08 +02:00
| AlphaEquiv ( l1 , l2 ) -> begin
if ( ( Lam . ( = ~ ) ) l1 l2 ) then
print_string " true \n "
else
print_string " false \n "
end ;
flush stdout
with e -> raise e
2024-04-09 11:09:33 +02:00
2024-04-16 11:40:08 +02:00
let _ = run ()
2024-04-09 11:09:33 +02:00