Soruma C kodundan çağrılan geri aramaları modelleyen arkadaş canlısı Haskell Arayüzleri nasıl yazılır. Geri aramalar burada (HaskellWiki) adreslenir, ancak bu sorunun bu bağlantıdan alınan örnekten daha karmaşık olduğuna inanıyorum.FFI Haskell Geri Arama Durumu
geri aramalar gerektiren biz C kodu olduğunu varsayalım ve başlık aşağıdaki gibidir: işlevi execution
bir geri çağırma işlevi alır ve yeni veri, esasen bir kapatma işlemek için kullanacaktır Bu durumda
typedef int CallbackType(char* input, char* output, int outputMaxSize, void* userData)
int execution(CallbackType* caller);
. Geri arama, bir giriş dizgisi, outputMaxSize
boyutunda tahsis edilmiş bir çıktı tamponu ve geri çağırma içinde dökülebilen userData işaretçisini bekler.
Haskell'de benzer şeyler yapıyoruz, MVars ile kapaklar etrafından geçtiğimizde, iletişim kurabiliyoruz. Bu yüzden Yabancı arayüzü yazdığımızda, bu tür bir tür tutmak isteriz. Özellikle burada
FFI Kodu gibi görünebilir şudur:
type Callback = CString -> CString -> CInt -> Ptr() -> IO CInt
foreign import ccall safe "wrapper"
wrap_callBack :: Callback -> IO (FunPtr Callback)
foreign import ccall safe "execution"
execute :: FunPtr Callback -> IO CInt
Kullanıcılar bu tür bir şey yapmak mümkün olmalıdır, ancak bunlar tip PTR ile geri aramalar yazmaya gerek beri fakir bir arayüzü gibi hissediyor(). Bunun yerine daha doğal olan MVars ile değiştirmek isteriz. Yani bir fonksiyon yazmak istiyorum:
myCallback :: String -> Int -> MVar a -> (Int, String)
myCallback input maxOutLength data = ...
gibi bir işlevi var, biz istiyoruz C'ye dönüştürmek amacıyla: castCallback çoğunlukla bu durumda
castCallback :: (String -> Int -> MVar a -> (Int, String))
-> (CString -> CString -> CInt -> Ptr() -> IO CInt)
main = wrap_callBack (castCallback myCallback) >>= execute
uygulamak zor değil, dizgiyi dönüştür -> cstring, Int -> CInt ve çıktı dizesinin üzerine kopyala. Bununla birlikte, zor kısım MVar'ı Ttr ile Ttr olarak, yani depolanmaya uygun olmayan bir şekilde çözmektedir.
Benim sorum, Haskell'de geri çağrılabilir kod yazmak için en iyi yoldur, bu da yine de iletilebilir.
Hiçbir şekilde bir FFI uzmanı değilim, fakat benim anlayışım C milletinin “void *” hilesini kullanmasıydı çünkü gerçek kapanışları yok. Haskell'de, gerçek kapanışlarımız var - bu nedenle, Haskell arabiriminden 'void *' argümanını kısmi uygulama yoluyla tüm yerel verilerin (belki de bir "IORef" veya "MVar") tamamen ve kapalı olarak bırakın. –
Ahh! Yakaladım. Bir deneyeyim. Bence bu bağlamanın yapmış olabileceği şeydi, ama ben bunu anlamadım. Cevabınız için teşekkürler! –
@tigger, DanielWagner'ın C'den Haskell'e senkronize geri çağrılması için önerdiği aynı hile yaptım - MVar argümanını uygulayarak kısmi bir işlev elde edin ve C fonksiyonunun MVar için verilerle geri çağırmasına izin verin. MVar'ınız daha karmaşıksa, verileri saklamak için Storable vektörünü veya depolanabilir bir örneği kullanabilirsiniz. Verileri C'den MVar'a geçirebilirsiniz. Ptr - Storable örneği C'ye geçirin. Burada bir örnek: http://hpaste.org/63702 – Sal