2012-07-02 14 views
5

Trong chương trình Haskell của tôi tôi có một ADT với nhiều nhà xây dựng:Cách xác định hàm tạo của dữ liệu từ mã nước ngoài?

data MyData = Con1 | 
    Con2 | 
    ... 
    Con20 

Tôi có một chức năng foreign export ccall, mà kết thúc tốt đẹp [MyData] vào mảng của StablePtr's. Sau khi gọi nó, tôi cần phải xác định constructor nào đã được sử dụng để xây dựng từng phần tử.

Nó có thể được giải quyết theo cách này

foreign export ccall getType :: StablePtr MyData -> IO CInt 
getType (Con1) = return 1 
getType (Con2) = return 2 
... 

nhưng sau đó tôi sẽ cần phải tự xác định các hằng số trong phần đầu C. Điều này là dễ bị lỗi, vì vậy tôi tự hỏi nếu có một cách để làm cho GHC làm công việc này cho tôi.

Trả lời

0

Tôi đã tìm thấy giải pháp cho việc này.

tôi đã xác định các loại nhà xây dựng có thể là enum trong mã C của tôi:

typedef enum 
{ 
    MyDataCon1, 
    MyDataCon2, 
    ... 
    MyDataCon20 
} MyDataConstructor; 

Sau đó tôi được sử dụng C->Haskell enum móc trong nguồn Haskell của tôi:

{#enum MyDataConstructor deriving (Show) #} 

Sau khi tiền xử lý dòng này quay sang

data MyDataConstructor = MyDataCon1 
    | MyDataCon2 
    ... 
    | MyDataCon20 

Bây giờ tôi có thể xác định getType theo cách này:

foreign export ccall getType :: StablePtr MyData -> IO CInt 
getType md = do 
    md' <- deRefStablePtr md 
    case md' of 
     Con1 -> return $ fromEnum MyDataCon1 
     Con2 -> return $ fromEnum MyDataCon2 
     ... 
     Con20 -> return $ fromEnum MyDataCon20 
5

phát sinh Enum cho loại Haskell của bạn và xuất fromEnumMyData :: MyData -> Int ; fromEnumMyData = fromEnum.

Sau đó, bạn có thể thực hiện phân tích trường hợp ở phía C bằng cách nhìn vào thẻ Int GHC gán.

+0

Xin lỗi, không hiểu. Làm cách nào để tôi biết nhà xây dựng nào đề cập đến một số thẻ? – arrowd

+0

Bạn không - nó được đưa ra theo thứ tự liệt kê. Tuy nhiên, bạn đã mất tất cả thông tin đó ở phía C, vì vậy bạn phải dựa vào một ánh xạ không an toàn. –

+0

Vì vậy, không thể tự động tạo bản đồ đó? – arrowd