2015-01-07 14 views
6

Tôi đang xây dựng trình chỉnh sửa đa phương thức bằng cách sử dụng reactive-banana - và phần lớn nó sẽ hoàn hảo. Để mở rộng trên kịch bản của tôi, trình soạn thảo là một số phần mềm lập bản đồ, hoặc bạn có thể nghĩ nó là một trình soạn thảo đồ họa vector rất đơn giản. Nó hiện có hai trạng thái - chế độ chọnchế độ tạo đa giác. Trong chế độ lựa chọn, người dùng có thể chọn đa giác được tạo trước đó bằng nút chuột phải (theo lý thuyết này sẽ đưa bạn đến một chế độ mới được chọn) hoặc họ có thể bắt đầu tạo đa giác mới bằng nút chuột trái.Thực hiện một công tắc duy nhất trong chuối phản ứng

Mục đích là, khi nhấn nút chuột trái, chúng tôi chuyển từ chế độ chọn sang chế độ tạo đa giác. Trong chế độ này, nút chuột trái có nghĩa là "thêm một đỉnh mới", cho đến khi người dùng quay lại đỉnh ban đầu. Tại thời điểm này, họ đã đóng đa giác, vì vậy chúng tôi trở lại chế độ lựa chọn.

Tôi đã triển khai thực hiện một số cách khác nhau và gần đây nhận thấy rằng sự kiện chuyển đổi gần như làm cho điều này rất thanh lịch. Tôi có thể có:

defaultMode :: Frameworks t => HadoomGUI -> Moment t (Behavior t Diagram) 
defaultMode [email protected]{..} = 
    do mouseMoved <- registerMotionNotify guiMap 
    mouseClicked <- registerMouseClicked guiMap 
    let lmbClicked = ... 
     gridCoords = ... 
     diagram = ... 
    switchToCreateSector <- execute ((\m -> 
             FrameworksMoment 
              (=<< trimB =<< createSectorMode gui emptySectorBuilder m)) <$> 
             (gridCoords <@ lmbClicked)) 
    return (switchB diagram switchToCreateSector) 

Cùng với

createSectorMode :: Frameworks t 
       => HadoomGUI 
       -> SectorBuilder 
       -> Point V2 Double 
       -> Moment t (Behavior t Diagram) 
createSectorMode HadoomGUI{..} initialSectorBuilder firstVertex = 
    do mouseClicked <- registerMouseClicked guiMap 
    ... 

Điều này chắc chắn làm việc - cho một click chuột duy nhất. Nếu tôi nhấp vào bản đồ một lần, tôi chuyển sang chế độ tạo ngành từ trạng thái tôi vừa nhập. Tuy nhiên, nếu tôi nhấp lại lần nữa, defaultMode nhận sự kiện nhấp và chuyển sang chế độ tạo đa giác mới . trạng thái trước đó.

Điều tôi muốn làm là chuyển đổi trong defaultMode một lần và không bao giờ có khả năng quay lại. Về cơ bản tôi muốn "hoán đổi" Behavior t Diagram được sản xuất bởi defaultMode với kết quả là createSectorMode.

Tôi hiểu reactive-banana gặp sự cố với thu thập rác của các sự kiện động, nhưng tôi sẵn sàng sống với điều đó ngay bây giờ. Công thức trên là chính xác hơn đáng kể so với bất cứ điều gì khác tôi đã viết cho đến nay - chẳng hạn như có một biến CurrentState duy nhất và lọc các sự kiện khác nhau dựa trên nội dung đó. Vấn đề tôi có với điều này là nó quá lớn, và để lại cách quá nhiều phạm vi cho tôi để mess những thứ lên. Với chuyển đổi, tôi chỉ có trong phạm vi các sự kiện tôi có thể.

Trả lời

3

Sự cố có phần mở kết thúc, vì vậy tôi không thể đưa ra câu trả lời rõ ràng. Nhưng tôi chắc chắn có thể đưa ra ý kiến ​​của tôi. ;-)

Tuy nhiên, những gì tôi có thể làm là tách chuyển đổi giữa các chế độ từ hành vi trong chế độ. Nếu chúng ta quên đi FRP trong chốc lát, chương trình của bạn trông hơi giống cặp chức năng mà đệ quy gọi mình:

defaultMode = ... `andthen` sectorMode 
sectorMode = ... `andthen` defaultMode 

Nó được viết một chút giống như một chương trình "tuần tự", "đầu tiên làm chế độ này, sau đó làm điều đó chế độ". Tôi nghĩ rằng không có gì sai với điều đó, mặc dù API phản ứng mặc định-chuối, đặc biệt là switchB, không hỗ trợ phong cách đó rất tốt. Bạn nói (tư nhân) mà bạn có thể viết một combinator

once :: Event t a -> Event t a 

cho phép thông qua sự xuất hiện đầu tiên của một sự kiện, nhưng loại bỏ phần còn lại. Đây thực sự là những gì bạn cần cho phong cách tuần tự.

Vì bạn luôn quay trở lại chế độ mặc định, tôi có thể thử một cách tiếp cận khác, trong đó mỗi chế độ có sự kiện cho biết rằng nó muốn được chuyển đi. Việc chuyển đổi chính nó được thực hiện bởi một thực thể "bên ngoài". Ý tưởng là để tránh sự đệ quy rõ ràng trong chương trình trên bởi một bộ kết hợp bậc cao hơn. Trong pseudo-code, điều này sẽ giống như thế này:

modeManager = switchB initialMode changeMode 
changeMode = defaultModeSwitch `union` sectorModeSwitch 

mặc dù tôi là một chút không chắc chắn về các chi tiết. Trong thực tế, tôi không hoàn toàn chắc chắn nếu nó hoạt động ở tất cả, bạn có lẽ vẫn cần các tổ hợp once.

Dù sao, đó chỉ là ý tưởng về cách chuyển đổi. Tôi hoàn toàn đồng ý rằng việc chuyển đổi là cách phù hợp để xử lý các chế độ khác nhau.

+0

Cảm ơn, đây là một cách tiếp cận thú vị mà tôi chưa từng cân nhắc. Bạn vẫn cần 'một lần' vì bạn vẫn gặp sự cố rằng" chế độ "cũ vẫn nhận được sự kiện, ngay cả khi họ yêu cầu được chuyển đi? Tôi chắc chắn sẽ có một vở kịch với điều này và xem những gì tôi tìm thấy. – ocharles

+0

Trong cả hai trường hợp, các chế độ cũ vẫn nhận được sự kiện - chỉ là bạn loại bỏ chúng/bỏ qua kết quả của chúng và thay vào đó tạo chế độ mới. Điều này có thể có nghĩa là bạn vẫn cần 'một lần' để đảm bảo rằng mỗi chế độ chỉ có thể báo hiệu một khi nó được thay thế bằng một cái mới. –

+0

Tôi không cho rằng đây là bộ sưu tập rác thải nào sẽ giúp giải quyết trong tương lai? – ocharles

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