2012-06-10 20 views
10

Tôi đã có những kiểu dữ liệu:Haskell: "bao nhiêu" của một loại chức năng sẽ nhận được? và tránh hoàn toàn "tái thiết"

data PointPlus = PointPlus 
    { coords :: Point 
    , velocity :: Vector 
    } deriving (Eq) 

data BodyGeo = BodyGeo 
    { pointPlus :: PointPlus 
    , size :: Point 
    } deriving (Eq) 

data Body = Body 
    { geo :: BodyGeo 
    , pict :: Color 
    } deriving (Eq) 

Đó là kiểu dữ liệu cơ sở cho các ký tự, kẻ thù, đối tượng, vv trong trò chơi của tôi (tốt, tôi chỉ có hai hình chữ nhật như các cầu thủ và mặt đất ngay bây giờ: p).

Khi một phím, các ký tự di chuyển sang phải, sang trái hoặc nhảy bằng cách thay đổi velocity của nó. Việc di chuyển được thực hiện bằng cách thêm velocity vào coords. Hiện nay, nó được viết như sau:

move (PointPlus (x, y) (xi, yi)) = PointPlus (x + xi, y + yi) (xi, yi) 

Tôi chỉ lấy PointPlus một phần của tôi Body và không phải là toàn bộ Body, nếu không nó sẽ là:

move (Body (BodyGeo (PointPlus (x, y) (xi, yi)) wh) col) = (Body (BodyGeo (PointPlus (x + xi, y + yi) (xi, yi)) wh) col) 

Là phiên bản đầu tiên của move tốt hơn ? Dù sao, nếu chỉ move chỉ thay đổi PointPlus, thì phải có một chức năng khác gọi hàm đó bên trong Body mới. Tôi giải thích: có một hàm update được gọi để cập nhật trạng thái trò chơi; nó đã được chuyển qua trạng thái trò chơi hiện tại, chỉ một số Body hiện tại và trả về số Body được cập nhật.

update (Body (BodyGeo (PointPlus xy (xi, yi)) wh) pict) = (Body (BodyGeo (move (PointPlus xy (xi, yi))) wh) pict) 

Điều đó làm tôi khó chịu. Mọi thứ được giữ nguyên trong Body ngoại trừ PointPlus. Có cách nào để tránh hoàn thành "tái thiết" này bằng tay không? Giống như trong:

update body = backInBody $ move $ pointPlus body 

Không cần phải xác định backInBody, tất nhiên.

Trả lời

14

Bạn đang tìm kiếm "ống kính". Có một số gói khác nhau cho ống kính; here là một bản tóm tắt tốt về chúng.

sự hiểu biết của tôi là một thấu kính trên một loại dữ liệu a đối với một số lĩnh vực b cung cấp hai hoạt động: một cách để có được giá trị của b và là một cách để có được một mới a với một giá trị khác nhau của b. Vì vậy, bạn sẽ chỉ sử dụng một ống kính để làm việc với các lồng nhau sâu sắc PointPlus.

Các gói thấu kính cung cấp các chức năng hữu ích để làm việc với thấu kính cũng như cách tạo ống kính tự động (với mẫu Haskell) có thể rất thuận tiện.

Tôi nghĩ rằng chúng đáng xem xét cho dự án của bạn, đặc biệt là vì bạn có thể gặp phải các vấn đề tương tự với việc lồng ghép ở những nơi khác nhờ cấu trúc của các loại dữ liệu của bạn.

+0

Điều đó hoàn hảo, đặc biệt là với thế hệ tự động! Còn chức năng 'move' thì sao? Có tốt hơn cho nó để lấy toàn bộ 'Body' hay chỉ là phần 'PointPlus' của nó? – L01man

+3

@ L01man Tôi cũng mô tả một ví dụ cụ thể rất giống với ví dụ của bạn trong một bài đăng trên blog của tôi về ống kính [ở đây] (http://www.haskellforall.com/2012/01/haskell-for-mainstream-programmers_28.html) –

+0

Việc giải thích từng bước của bạn đã giúp tôi hiểu thấu kính hoàn toàn. – L01man

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