2012-02-11 24 views
6

Xuất phát từ nền Java, tôi khá thích an toàn kiểu tĩnh và tự hỏi các lập trình viên clojure xử lý vấn đề định nghĩa dữ liệu như thế nào (có lẽ không chỉ là các kiểu bất biến chung. trường hợp đặc biệt đó.)An toàn định dạng dữ liệu trong clojure

Điều này tương tự như câu hỏi hiện có "Loại an toàn trong Clojure", nhưng điều đó tập trung nhiều hơn vào khía cạnh của cách kiểm tra loại tại thời gian biên dịch, trong khi tôi quan tâm nhiều hơn đến cách vấn đề là thực tế giải quyết.

Ví dụ thực tế tôi đang xem xét một ứng dụng trình soạn thảo xử lý một định dạng tài liệu cụ thể. Mỗi tài liệu bao gồm các phần tử có nhiều loại khác nhau (các yếu tố đồ họa, các phần tử phông chữ, v.v.) Sẽ có các trình soạn thảo cho các loại phần tử khác nhau và các hàm của khóa học để chuyển đổi một tài liệu từ/sang luồng byte. định dạng đĩa.

Vấn đề cơ bản mà tôi quan tâm là các trình chỉnh sửa và các chức năng đọc/ghi phải đồng ý trên một định dạng dữ liệu chung. Trong Java, tôi sẽ mô hình dữ liệu của tài liệu dưới dạng đồ thị đối tượng, ví dụ: với một lớp đại diện cho một tài liệu và một lớp cho mỗi loại phần tử. Bằng cách này, tôi nhận được một sự đảm bảo thời gian biên dịch về cấu trúc dữ liệu của tôi trông như thế nào, và trường "chiều rộng" của phần tử đồ họa là một số nguyên chứ không phải là một phao. Nó không đảm bảo rằng chiều rộng là dương - nhưng bằng cách sử dụng một giao diện getter/setter sẽ cho phép lớp tương ứng thêm các bảo đảm bất biến như thế.

Có thể dựa vào điều này làm cho mã xử lý dữ liệu này đơn giản hơn, và định dạng vi phạm có thể bị bắt vào thời gian biên dịch hoặc đầu thời gian chạy (nơi một số mã cố sửa đổi dữ liệu vi phạm bất biến).

Làm cách nào để bạn có thể đạt được "độ tin cậy định dạng dữ liệu" tương tự trong Clojure? Theo tôi biết, không có cách nào để thực hiện việc kiểm tra và ẩn dữ liệu miền sau một giao diện chức năng dường như không được khuyến khích vì không phải là thành ngữ (hoặc có thể tôi hiểu sai?), Vậy các nhà phát triển Clojure làm gì để cảm thấy an toàn định dạng dữ liệu được đưa vào chức năng của chúng? Làm cách nào để mã của bạn bị lỗi càng nhanh càng tốt, chứ không phải sau khi người dùng chỉnh sửa thêm 20 phút và cố gắng lưu vào đĩa, khi chức năng lưu lưu ý rằng có phần tử đồ họa trong danh sách phông chữ do lỗi trình soạn thảo? Vui lòng lưu ý rằng tôi quan tâm đến Clojure và học tập, nhưng không viết bất kỳ phần mềm thực sự nào với nó, vì vậy có thể tôi chỉ bối rối và câu trả lời rất đơn giản - nếu có, xin lỗi vì lãng phí thời gian của bạn :).

Trả lời

8

Tôi không thấy bất kỳ điều gì sai hoặc không đơn giản về việc sử dụng API xác thực để xây dựng và thao tác dữ liệu của bạn như sau.

(defn text-box [text height width] 
    {:pre [(string? text) (integer? height) (integer? width)]} 
    {:type 'text-box :text text :height height :width width}) 

(defn colorize [thing color] 
    {:pre [(valid-color? color)]} 
    (assoc thing :color color)) 

... (colorize (text-box "Hi!" 20 30) :green) ... 

Bên cạnh đó, tài liệu tham khảo (vars, refs, các nguyên tử, đại lý) có thể có một liên validator function có thể được sử dụng để đảm bảo trạng thái có giá trị tại mọi thời điểm.

+0

Cảm ơn câu trả lời cho đến nay. Vì đây là một câu hỏi khá cởi mở, tôi sẽ đợi thêm một chút trước khi chấp nhận. Hàm validator giống như một giải pháp thú vị, mặc dù bạn có một tài liệu lớn như trạng thái của bạn, xác nhận nó hoàn toàn mỗi khi một thay đổi nhỏ được thực hiện có vẻ không hiệu quả - trong mô hình như vậy, tôi đoán sử dụng xác nhận các chức năng thao tác sẽ thích hợp hơn. – Medo42

5

Câu hỏi hay - Tôi cũng thấy rằng việc chuyển từ ngôn ngữ được nhập tĩnh sang ngôn ngữ động đòi hỏi phải quan tâm nhiều hơn đến an toàn loại. May mắn là kỹ thuật TDD giúp một lượng lớn ở đây.

Tôi thường viết chức năng "xác thực" để kiểm tra tất cả các giả định của bạn về cấu trúc dữ liệu. Tôi cũng thường làm điều này trong Java cho các giả định bất biến, nhưng trong Clojure nó quan trọng hơn vì bạn cần phải kiểm tra suy nghĩ giống như các loại.

Sau đó bạn có thể sử dụng chức năng validate bằng nhiều cách:

  • Như một kiểm tra nhanh tại REPL: (validate foo)
  • Trong các thử nghiệm đơn vị: (is (validate (new-foo-from-template a b c)))
  • Như một tấm séc thời gian chạy cho các chức năng quan trọng , ví dụ kiểm tra xem (read-foo some-foo-input-stream) có hợp lệ không

Nếu bạn có cấu trúc dữ liệu phức tạp là một loại thành phần khác nhau, bạn có thể xác thực hàm cho toàn bộ cuộc gọi tài liệu xác thực từng thành phần phụ đệ quy. Một mẹo hay là sử dụng một trong hai giao thức hoặc đa phương thức để làm cho đa hình chức năng xác thực cho từng loại thành phần.

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