OCaml相当于Python生成器

时间:2015-02-05 20:29:45

标签: python ocaml generator

法国SécuritéSociale标识号以两位数的校验码结尾。我已经确认可以检测到每个可能的common transcription error,并发现一些其他类型的错误(例如。,滚动三个连续的数字),这些错误可能无法检测到。

def check_code(number):
    return 97 - int(number) % 97

def single_digit_generator(number):
    for i in range(len(number)):
        for wrong_digit in "0123456789":
            yield number[:i] + wrong_digit + number[i+1:]

def roll_generator(number):
    for i in range(len(number) - 2):
        yield number[:i] + number[i+2] + number[i] + number[i+1] + number[i+3:]
        yield number[:i] + number[i+1] + number[i+2] + number[i] + number[i+3:]

def find_error(generator, number):
    control = check_code(number)
    for wrong_number in generator(number):
        if number != wrong_number and check_code(wrong_number) == control:
            return (number, wrong_number)

assert find_error(single_digit_generator, "0149517490979") is None
assert find_error(roll_generator, "0149517490979") == ('0149517490979', '0149517499709')

我的Python 2.7代码(上面的工作片段)大量使用生成器。我想知道如何在OCaml中调整它们。我当然可以编写一个维护内部状态的函数,但我正在寻找一个纯粹的功能解决方案。我可以研究一下我不太熟悉的图书馆lazy吗?我不是要求代码,只是方向。

2 个答案:

答案 0 :(得分:8)

您可以使用语言的扩展名将生成器定义为

let range n = Stream.from (fun i -> if i < n then Some i else None);;

for句法结构不能与之一起使用,但Stream模块提供了一组函数来检查流的状态并迭代其元素。

try
  let r = range 10 in
  while true do
    Printf.printf "next element: %d\n" @@ Stream.next r
  done
with Stream.Failure -> ();;

或更简单:

Stream.iter (Printf.printf "next element: %d\n") @@ range 10;;

您也可以使用 camlp4 预处理器提供的特殊语法:

Stream.iter (Printf.printf "next element: %d\n") [< '11; '3; '19; '52; '42 >];;

其他功能包括从列表,字符串,字节甚至通道创建流。 API documentation 简洁地描述了不同的可能性。

使用特殊语法组合它们,以便在之前或之后放回元素,但最初可能有点不直观:

let dump = Stream.iter (Printf.printf "next element: %d\n");;

dump [< range 10; range 20 >];;

将生成第一个流的元素,然后在最后一个生成元素的等级之后的元素中拾取第二个流,因此它将在这种情况下显示为好像只有第二个流被迭代了。

要获取所有元素,您可以构造一个'a Stream.t的流,然后递归迭代每个元素:

Stream.iter dump [< '(range 10); '(range 20) >];;

这些会产生预期的输出。

我建议您阅读有关OCaml的旧书(可用online),以便更好地介绍该主题。

答案 1 :(得分:5)

Core库以python样式提供生成器,请参阅Sequence module。

这是一个例子,取自我的一个项目:

open Core_kernel.Std

let intersections tab (x : mem) : _ seq =
  let open Sequence.Generator in
  let init = return () in
  let m = fold_intersections tab x ~init ~f:(fun addr x gen ->
      gen >>= fun () -> yield (addr,x)) in
  run m