2012-07-02 9 views
5

W moim programie Haskell Mam ADT z wielu konstruktorów:Jak ustalić konstruktor danych z obcego kodu?

data MyData = Con1 | 
    Con2 | 
    ... 
    Con20 

Mam foreign export ccall funkcję, która otacza [MyData] na tablicy StablePtr's. Po wywołaniu muszę ustalić, który konstruktor został użyty do skonstruowania każdego elementu.

To może być rozwiązany w ten sposób

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

ale wtedy musiałby ręcznie zdefiniować te stałe w C cel. Jest to podatne na błędy, więc zastanawiam się, czy istnieje sposób, aby GHC wykonał dla mnie tę pracę.

Odpowiedz

0

Znalazłem rozwiązanie do tego.

Mam zdefiniowane możliwe rodzaje konstruktora jak enum w moim kodu C:

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

Następnie użyłem C->Haskell hak enum w moim źródle Haskell:

{#enum MyDataConstructor deriving (Show) #} 

Po przerób ten wiersz zamienia się

data MyDataConstructor = MyDataCon1 
    | MyDataCon2 
    ... 
    | MyDataCon20 

Teraz mogę zdefiniować getType w ten sposób:

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

wywodzących się z Enum dla Twojego typu Haskell i eksportować fromEnumMyData :: MyData -> Int ; fromEnumMyData = fromEnum.

Następnie można wykonać analizę przypadku po stronie C, patrząc na przypisania GHC tagu Int.

+0

Niestety, nie udało się. Skąd mam wiedzieć, do którego konstruktora odwołuje się jakiś znacznik? – arrowd

+0

Nie robisz tego - wynika to z porządkowania wyliczenia. Ale i tak straciłeś już wszystkie informacje na stronie C, więc musisz polegać na niebezpiecznym mapowaniu. –

+0

Więc nie jest możliwe automatyczne wygenerowanie tego mapowania? – arrowd

Powiązane problemy