我的代码:
getGPS :: String -> IO (Double, Double) getGPS ip = do html <- getHTML ip let ztags =Prelude.zip [0..] . filterStr . getTagText . getTags $ html let nlat = Prelude.head $ Prelude.map fst . Prelude.filter (\(_, str) -> strEq str ("Latitude:" :: String)) $ ztags let nlng = Prelude.head $ Prelude.map fst . Prelude.filter (\(_, str) -> strEq str ("Longitude:" :: String)) $ ztags let lat = read (Prelude.head $ Prelude.map snd . Prelude.filter (\(n, _) -> n == nlat + 1) $ ztags) :: Double let lng = read (Prelude.head $ Prelude.map snd . Prelude.filter (\(n, _) -> n == nlng + 1) $ ztags) :: Double return (lat, lng)
工作正常.现在我想导出这个函数FFI
来从C应用程序访问它.我做了foreign export ccall getGPS :: CString -> IO (CDouble, CDouble)
但这不起作用:
GPS.hs:45:1: Illegal foreign declaration: requires unregisterised, llvm (-fllvm) or native code generation (-fasm) When checking declaration: foreign export ccall "getGPS" getGPS :: CString -> IO (CDouble, CDouble) GPS.hs:45:1: Unacceptable result type in foreign declaration: ‘(CDouble, CDouble)’ cannot be marshalled in a foreign call When checking declaration: foreign export ccall "getGPS" getGPS :: CString -> IO (CDouble, CDouble) GPS.hs:45:1: Couldn't match type ‘Double’ with ‘CDouble’ Expected type: CString -> IO (CDouble, CDouble) Actual type: String -> IO (Double, Double) In the expression: getGPS When checking declaration: foreign export ccall "getGPS" getGPS :: CString -> IO (CDouble, CDouble) Failed, modules loaded: none.
如何正确导出此功能?
实际上有两个错误:
foreign export
和getGPS
函数的类型必须匹配,所以你需要从CString到CDouble的GPS包装器(使用peekCString
并CDouble
转换它们)
你不能使用元组作为返回参数.有多种解决方案,比如使用2个Ptr CDouble
参数或定义结构.
所以可能的解决方案是
foreign export ccall "getGPS" getGPS' :: CString -> Ptr CDouble -> Ptr CDouble -> IO () getGPS' :: CString -> Ptr CDouble -> Ptr CDouble -> IO () getGPS' str d1 d2 = do (r1, r2) <- getGPS =<< peekCString str poke d1 (CDouble r1) poke d2 (CDouble r2)
记得打电话hs_init
和hs_exit
使用C代码时.