2012-03-23 32 views
6

Có mẫu thiết lập nào để triển khai chức năng hoàn tác/làm lại trong clojure hoặc trong fp nói chung không?mẫu để thực hiện hoàn tác/làm lại trong clojure

Trong ngôn ngữ OO, tôi sẽ đi với mẫu lệnh nhưng vì đó là tất cả về trạng thái, tôi tự hỏi nếu nó là thành ngữ làm nó trong clojure.

Có thư viện nào có thể trợ giúp không?

+0

Câu hỏi trước là liệu bạn có thực sự cần đột biến trạng thái này ngay từ đầu hay không. –

+0

@Alex Taggart: và tất nhiên bạn thực sự không (nhưng tôi lấy nó là quan điểm của bạn;) Tôi đã viết hoàn tác/làm lại chỉ sử dụng các đối tượng bất biến (trong Java). Bạn có thể viết hoàn tác/làm lại bằng cách chỉ lưu (đầu vào của người dùng) và bằng cách tạo lại "trạng thái" bằng cách phát lại các yếu tố đầu vào của bạn đến thời gian mong muốn. Vì vậy, khi bạn muốn hoàn tác từ "t5 đến t4", bạn không "tua lại" từ t5 đến t4, nhưng bạn phát lại các đầu vào từ t0 đến t4 (và bởi vì bạn đang thực hiện theo cách "chức năng", bạn đảm bảo kết thúc với trạng thái chính xác). Hoạt động trong nhiều trường hợp và đơn giản hóa rất nhiều việc thực hiện hoàn tác/làm lại IMHO ... – TacticalCoder

Trả lời

5

Giống như với nhiều mẫu thiết kế, bạn có thể triển khai mẫu này làm chức năng trong clojure. Nó phụ thuộc một chút vào cách bạn đại diện cho nhà nước trong chương trình của bạn (refs, nguyên tử, đại lý) thông qua quá trình này là rất giống nhau.

Bạn có thể chỉ cần thêm chức năng xem vào trạng thái của bạn tác nhân/ref/atom thêm trạng thái vào danh sách hoàn tác mỗi khi có bản cập nhật. sau đó chức năng hoàn tác của bạn chỉ hiển thị trong danh sách hoàn tác. Điều này có tác dụng tốt đẹp khi thêm bản sao của bạn vào danh sách hoàn tác, cho phép làm lại cũng như

Ấn tượng đầu tiên của tôi là ref s có thể là công cụ chính xác vì bạn sẽ có thể khôi phục tất cả theo cách phối hợp , trừ khi tất nhiên bạn có thể giảm bớt các chương trình của bạn xuống một danh tính duy nhất (theo ý nghĩa của từ Clojure) thì bạn sẽ không cần cập nhật phối hợp và một tác nhân sẽ làm việc.

+0

Cảm ơn bạn. Điều đó nghe có vẻ giống như một giải pháp tốt đẹp. Nhưng để xem liệu tôi có nhận được quyền này không: Tôi có 3 lần phản hồi đại diện cho tiểu bang của tôi. tôi gọi thêm đồng hồ trên mỗi người trong số họ. Khi một số hoặc tất cả chúng bị thay đổi trong một giao dịch, người xem sẽ chụp nhanh tất cả chúng và đặt nó lên một chồng. Chức năng hoàn tác sẽ mở một giao dịch mới và khôi phục trạng thái ảnh chụp nhanh cuối cùng trong tất cả các lần chỉnh sửa của tôi. – nansen

+0

Có. Tôi cho rằng một cái gì đó cần phải đảm bảo rằng ba người theo dõi không thêm cùng một trạng thái vào ngăn xếp ba lần. –

+1

. Tôi cũng có thể sống với việc tập hợp tất cả thông tin trạng thái vào một nguyên tử duy nhất. Điều này sẽ làm cho quá trình chuyển đổi dễ dàng hơn nhiều. – nansen

1

Ok tôi đã làm cho nó làm việc như Arthur Ulfeldt gợi ý:

(defn cmd-stack [state-ref] 
    (let [stack (atom ['() '()])] 
    (add-watch state-ref :cmdhistory 
      (fn [key ref old new] 
      (let [redo-stack '() 
        undo-stack (conj (second @stack) old)] 
      (reset! stack [redo-stack undo-stack])))) 
    stack)) 

(defn can-redo? [stack] 
    (not (empty? (first @stack)))) 

(defn can-undo? [stack] 
    (not (empty? (second @stack)))) 

(defn undo! [stack state-ref] 
    (let [redo-stack (first @stack) 
     undo-stack (second @stack) 
     current-state @state-ref 
     last-state (first undo-stack)] 
    (assert (can-undo? stack) "cannot undo") 
    (reset! state-ref last-state) 
    (reset! stack [(conj redo-stack current-state) (drop 1 undo-stack)]))) 

(defn redo! [stack state-ref] 
    (let [redo-stack (first @stack) 
     undo-stack (second @stack) 
     current-state @state-ref 
     last-state (first redo-stack)] 
    (assert (can-redo? stack) "cannot redo") 
    (reset! state-ref last-state) 
    (reset! stack [(drop 1 redo-stack) (conj undo-stack current-state)]))) 

Nhưng những gì tôi vẫn không hoàn toàn hiểu là tại sao. Kể từ khi hoàn tác! và làm lại! chức năng cập nhật các nguyên tử đang được theo dõi, không nên người xem phản ứng với điều đó và do đó mess up stack lệnh bằng cách đặt giá trị undone trở lại vào nó?

+0

Câu hỏi về việc hoàn tác hoàn tác yêu cầu phải suy nghĩ. Bạn có muốn hai lần hoàn tác liên tiếp tương đương với hoàn tác và sau đó làm lại không? –

+0

câu trả lời này có thể được thể hiện tốt hơn dưới dạng bản chỉnh sửa cho câu hỏi gốc. –

+0

@Arthur: câu hỏi đầu tiên: không, tôi dĩ nhiên không mong đợi một hành vi như vậy. Đó không phải là ý tôi. Tôi có nghĩa là, rằng tôi đã có thể dự kiến ​​mã trên là sai (như bạn mô tả) nhưng nó thực sự hành xử một cách chính xác. Ít nhất là theo các bài kiểm tra đơn vị ;-). Bình luận thứ hai của bạn: Tôi đã suy nghĩ rằng quá đầu tiên, nhưng sau đó tìm thấy, rằng bài viết thực sự là một câu trả lời cho câu hỏi ban đầu của tôi, chỉ có một trong đó đặt ra một câu hỏi khác. – nansen

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