2015-02-05 19 views
6

Pháp Sécurité Sociale số nhận dạng kết thúc bằng mã kiểm tra gồm hai chữ số. Tôi đã xác minh rằng mọi khả năng common transcription error có thể được phát hiện và tìm thấy một số loại lỗi khác (, ví dụ:, ba chữ số liên tiếp) có thể không bị phát hiện.OCaml tương đương với máy phát Python

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

def single_digit_generator(number): 
    for i in range(len(number)): 
     for wrong_digit in "": 
      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') 

Mã Python 2.7 (đoạn làm việc ở trên) sử dụng nhiều máy phát. Tôi đã tự hỏi làm thế nào tôi có thể thích ứng với họ trong OCaml. Tôi chắc chắn có thể viết một chức năng duy trì một số trạng thái nội bộ, nhưng tôi đang tìm kiếm một giải pháp hoàn toàn chức năng. Tôi có thể nghiên cứu thư viện lazy mà tôi không quá quen thuộc không? Tôi không yêu cầu mã, chỉ cần hướng dẫn.

Trả lời

4

Bạn chỉ có thể xác định một máy phát điện như một dòng suối , sử dụng phần mở rộng của ngôn ngữ:

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

Các Cấu trúc cú pháp for không thể được sử dụng với điều đó, nhưng có một tập hợp các hàm được cung cấp bởi mô-đun Stream để kiểm tra trạng thái của luồng và lặp lại trên các phần tử của nó.

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

Hoặc đơn giản hơn:

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

Bạn cũng có thể sử dụng một cú pháp đặc biệt được cung cấp bởi các camlp4 Preprocessor:

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

tính năng khác bao gồm việc tạo ra các luồng ra khỏi danh sách, chuỗi , byte hoặc thậm chí kênh. API documentation mô tả ngắn gọn các khả năng khác nhau.

Cú pháp đặc biệt cho phép bạn soạn chúng, để đưa trở lại các yếu tố trước hoặc sau, nhưng nó có thể hơi unintuitive lúc đầu:

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

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

sẽ sản xuất các yếu tố của dòng đầu tiên, và sau đó chọn dòng thứ hai ở phần tử được xếp hạng ngay sau thứ hạng của phần tử được mang lại cuối cùng, do đó, nó sẽ xuất hiện trong trường hợp này như thể chỉ luồng thứ hai được lặp lại.

Để có được tất cả các yếu tố, bạn có thể xây dựng một dòng 'a Stream.t và sau đó đệ quy lặp trên mỗi:

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

Những sẽ tạo ra kết quả mong đợi.

Tôi khuyên bạn nên đọc sách cũ trên OCaml (có sẵn online) để có giới thiệu tốt hơn về chủ đề.

4

Core thư viện cung cấp máy phát theo kiểu python, xem mô-đun Sequence.

Dưới đây là một ví dụ, lấy từ một trong những dự án của tôi:

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 
+0

Bất kỳ liên kết nào? Bạn có nói về mô-đun này ['Seq'] (http://batteries.forge.ocamlcore.org/doc.preview:batteries-beta1/html/api/Seq.html) không? – Aristide

+0

Tôi đã thêm liên kết vào các mô-đun tương ứng. 'Seq' chỉ là bí danh của riêng tôi cho' Sequence'. Tôi đã đổi tên nó trở lại. Bạn có thể tìm thêm ví dụ về các liên kết được cung cấp. – ivg

+0

Bạn có thể muốn xem xét chỉ cần mở Or_error.Monad_infix, thay vì toàn bộ mô-đun Or_error. Nói chung tốt hơn để mở ít hơn là nhiều hơn ... – yzzlr

Các vấn đề liên quan