OCaml 相当于 Python 个生成器
OCaml equivalent of Python generators
法国 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
吗?我不是要代码,只是要方向。
Core
library provides generators in a python style, see Sequence
模块。
这是一个例子,取自我的一个项目:
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
您可以简单地将生成器定义为 流,使用语言的扩展:
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)以获得对该主题的更好介绍。
法国 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
吗?我不是要代码,只是要方向。
Core
library provides generators in a python style, see Sequence
模块。
这是一个例子,取自我的一个项目:
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
您可以简单地将生成器定义为 流,使用语言的扩展:
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)以获得对该主题的更好介绍。