递归函数和异常处理

时间:2014-12-22 09:25:40

标签: list recursion ocaml

我正在构建一个浮点计算器而且我被卡住了。 fp计算器有快速的形状,所以我的问题是,在我处理异常的地方,我留下了递归函数,使得提示出现并结束执行:

let initialDictionary = ref EmptyDictionary;;

let launcher () = 
   print_string ("Welcome");
   let rec aux dic =
        try 
           print_string ("->");
           aux ( execute dic (s token (Lexing.from_string (read_line () ))));
         with
             End_of_exec -> print_endline ("closing")
             Var_not_assigned s -> printf "var %s not assigned" s
             in aux !initialDictionary;;

其中:

val exec : dictionary -> Instruction -> dictionary;
type dictionary = (string,float)list

这里的要点是,由于列表在ocaml上是不可变的,我必须保持我的字典堆栈变量及其值的唯一方法是应用递归从exec返回获取值字典。

那么关于如何在显示异常时不离开“提示式”执行的任何想法?

2 个答案:

答案 0 :(得分:1)

read eval print loop解释器具有所有这些不同的阶段,必须单独处理,我认为您的实现试图在一个步骤中做太多。打破函数的第二部分将有助于解开不同的错误处理程序:

let launcher () =
    let rec prompt dic =
        print_string "->";
        parse dic
    and parse dic =
        let res =
            try
                s token (Lexing.from_string @@ read_line ())
            with End_of_exec -> (print_encline "closing"; raise End_of_exec)
        in evalloop dic res
    and evalloop dic rep =
        let dic =
            try execute dic rep
            with Var_not_assigned s -> (printf "var %s not assigned\n" s; dic)
        in prompt dic
    in prompt !InitialDictionary;;

由于每个子函数都是tail call下一个或者因异常而失败,因此整个代码应该是尾递归并优化为循环。

关于这一点的好处是,现在您可以更好地了解正在发生的事情,并且可以更轻松地更改循环的单个步骤而不会触及其余部分。

顺便提一下,回想一下,read_line也可能触发End_of_file例外,但现在应该处理这个例子(作为练习留下来)。

答案 1 :(得分:1)

好吧,我的一个朋友给了我一个解决方案并思考它我无法找到一个更优雅的方式。

Let exec () =
   Let _= print_string "->" in
   ( try 
       Let inst = s token (Lexing.from_string (read_line())) in
      Try
        Let r = exec_instruction !initialDictionary inst in
        initialDictionary := r
      With
        | Var_not_assigned s -> printf "var %s not assigned. \n" s
        | Com_not_implemented s -> printf " command %s not implemented. \n" s
        | Function_not_implemented s -> printf " function %s not implemented. \n" s
   With
      | lexic_error -> print_endline "lexic error"
      | Parsing. Parse_error -> print_endline "sintax error"

);;

Let rec program cont =
If cont then
  Try
    Exec (); program true
  With
     | End_of_exec -> print_endline "closing"; program false;;

Program true

唯一困扰我initialDictionary := r赋值的东西,因为exec_instruction返回一个字典,所以它可以递归完成,但无论如何都可以工作,生病了哈哈。 感谢您的帮助,如果有人能看到一个解决方案让我知道。