【问题标题】:OCaml checking functionsOCaml 检查函数
【发布时间】:2015-10-09 16:30:45
【问题描述】:

我想定义一个函数 check_char_fun: (char -> 'a) -> (char ->' a) -> bool that,给定两个函数 在 char 上,当两个函数相同时返回 true(即,当它们在 char 的每个可能值上的行为完全相同时),否则返回 false。

let check_char_fun f1 f2 =
let aux = true
for i=0 to 255 do
    if (f1 (char_of_int i))=(f2 (char_of_int i))
    then aux=false;
done;
if aux=true
then true
else false;;

我正在学习OCaml,所以我不知道我能做什么。

【问题讨论】:

    标签: ocaml


    【解决方案1】:

    你快到了:

    let check_char_fun f1 f2 =
      let aux = ref true in
      for i = 0 to 255 do
        if (f1 (char_of_int i)) = (f2 (char_of_int i)) then aux := false
        else ()
      done;
      !aux
    

    与命令式语言中的变量不同,OCaml 中的绑定默认是不可变的。为了创建一个真正的变量,我们创建了一个bool ref,它是可变的并且可以在循环中改变。

    OCaml 不像命令式语言那样区分语句和表达式:只有表达式!这就是为什么你总是需要else 子句到if;这样,结果表达式总是返回一个值(在ifelse 的情况下),其类型必须相同——在这种情况下为unit 类型(值() 的类型——这将是 C 中的void)。

    你的代码不是很像 OCaml,但这就是我个人喜欢 OCaml 的地方:函数式风格不会强行进入你的喉咙,你可以在不进入学术象牙塔的情况下以命令式风格实现算法。

    【讨论】:

      【解决方案2】:

      首先,您必须定义“行为”是什么。如果您的函数可以引发异常,那么问题就会变得更加困难。您的代码假定函数始终返回一个值,这对于刚开始的问题来说似乎是一个很好的简化。

      您还使用了 OCaml 使用的(有点过时的)字符定义,因为代码被限制在 0 .. 255 的范围内。这似乎也可以。

      所以我在您的代码中看到的唯一问题是您希望能够更改aux 变量的值。 OCaml 中的变量是不可变的:您无法更改它们绑定的值。

      如果您希望大部分代码保持原样,您可以更改aux,使其值为 reference 到 bool。然后您可以更改引用内部的布尔值(而aux 仍然绑定到相同的引用)。

      引用布尔值并更改值:

      # let x = ref true;;
      val x : bool ref = {contents = true}
      # !x;;
      - : bool = true
      # x := false;;
      - : unit = ()
      # !x;;
      - : bool = false
      

      (学习 OCaml 的原因之一是学习如何使用不可变值。所以我建议寻找其他方法来解决不需要使用引用的问题。)

      【讨论】:

        【解决方案3】:
        let rec range i j = 
          if i > j then [] else i :: (range (i+1) j);;
        
        let check_char_fun f1 f2 =
          let lc = List.map char_of_int (range 0 255) in
          List.for_all (fun c -> (f1 c) = (f2 c)) lc;;
        

        测试:

        #let id x =x;;
        val id : 'a -> 'a = <fun>
        # check_char_fun id id;;
        - : bool = true
        # check_char_fun id (fun x -> 'a');;
        - : bool = false
        

        或者:

        exception Fails_in of char;;
        let check_char_fun f1 f2 =
          let lc = List.map char_of_int (range 0 255) in
          List.iter (fun c ->  
            if (f1 c) <> (f2 c) then raise (Fails_in c)
          ) lc;;
        
        # try (
          check_char_fun id id
        ) with Fails_in c -> Printf.printf "Diff(%d)(%c)" (int_of_char c) c
        ;;
          - : unit = ()
        
        
        # try (
          check_char_fun id (fun x -> 'a')
        ) with Fails_in c -> Printf.printf "Diff(%d)(%c)" (int_of_char c) c
        ;;      
        Diff(0)()- : unit = ()
        

        【讨论】:

        • 现在我创建了:异常Fails_in of char;我想定义相同的函数 Check_char_fun 但我认为它必须是 (char -> 'a) -> (char ->' a) -> unit 如果我想抛出异常。因此,如果 f1 和 f2 是同一个函数,则 check_char_fun f1 f2 返回 (),如果 c 是一个字符,而 f1 c 和 f2 c 不是同一个函数,则返回 Fails_in c。我不能用 List.map 做,可以吗?
        • @ChenYo:若要在不匹配时获取异常,请将传递给List.for_all 的函数主体更改为(f1 c) = (f2 c) || raise (Fails_in c)
        【解决方案4】:

        以下将每个函数应用于 0 .. 255 范围内的每个字符值并比较它们的结果,但它不检查函数引发异常或在其他地方引起副作用的情况:

        open Core.Std
        let check_char_fun f1 f2 =
          let chars = List.map ~f:char_of_int (List.range 0 256) in
          List.for_all ~f:(fun c -> (f1 c) = (f2 c)) chars
        

        【讨论】:

        • 标准库中没有List.range,也没有List.for_all 的标记版本(在这种情况下,使用标记参数似乎是一种不必要的干扰)。
        • 他们在Core.Std
        猜你喜欢
        • 1970-01-01
        • 2017-03-04
        • 2012-10-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-06-30
        • 2016-07-09
        相关资源
        最近更新 更多