如何在Haskell FFI到C ++中编写纯字符串到字符串函数
我想通过Haskell FFI在C ++中实现一个函数,它应该有(最终)类型的String -> String
。 说,是否有可能在C ++中使用完全相同的签名重新实现以下函数?
import Data.Char
toUppers:: String -> String
toUppers s = map toUpper s
特别是,我想避免在返回类型中使用IO,因为为这个简单的任务引入杂质(我的意思是IO monad)在逻辑上是不必要的。 到目前为止,我所见过的一个C字符串的所有例子都涉及返回一个不能转换回纯String
的IO或Ptr。
我想这样做的原因是,我觉得编组对FFI来说很混乱。 也许如果我可以修复上面最简单的情况(除了像int这样的基本类型),那么我可以在C ++端做任何我想要的数据解析,这应该很容易。
与我想在编组字符串之间进行的计算相比,解析的成本可以忽略不计。
提前致谢。
至少在某些时候需要涉及IO
,为C字符串分配缓冲区。 这里直接的解决方案可能是:
import Foreign
import Foreign.C
import System.IO.Unsafe as Unsafe
foreign import ccall "touppers" c_touppers :: CString -> IO ()
toUppers :: String -> String
toUppers s =
Unsafe.unsafePerformIO $
withCString s $ cs ->
c_touppers cs >> peekCString cs
在我们使用withCString
将Haskell字符串编组为缓冲区的情况下,将其更改为大写,最后将(更改!)缓冲区内容解组到新的Haskell字符串中。
另一种解决方案可能是将IO
混乱委托给bytestring
库。 无论如何,如果你对表演感兴趣,这可能是个好主意。 该解决方案大致如下所示:
import Data.ByteString.Internal
foreign import ccall "touppers2"
c_touppers2 :: Int -> Ptr Word8 -> Ptr Word8 -> IO ()
toUppers2 :: ByteString -> ByteString
toUppers2 s =
unsafeCreate l $ p2 ->
withForeignPtr fp $ p1 ->
c_touppers2 l (p1 `plusPtr` o) p2
where (fp, o, l) = toForeignPtr s
这更优雅一些,因为我们现在不需要进行任何编组,只需转换指针即可。 另一方面,C ++端在两个方面发生了变化 - 我们必须处理非空终止的字符串(需要传递长度),现在必须写入不同的缓冲区,因为输入不再是副本。
作为参考,这里有两个适合上述导入的快捷C ++函数:
#include <ctype.h>
extern "C" void touppers(char *s) {
for (; *s; s++) *s = toupper(*s);
}
extern "C" void touppers2(int l, char *s, char *t) {
for (int i = 0; i < l; i++) t[i] = toupper(s[i]);
}
链接地址: http://www.djcxy.com/p/61181.html
上一篇: How to write a pure String to String function in Haskell FFI to C++