gpt4 book ai didi

string - 如何在 Haskell 中编写纯字符串到字符串函数 FFI 到 C++

转载 作者:行者123 更新时间:2023-12-02 09:24:35 24 4
gpt4 key购买 nike

我想通过 Haskell FFI 在 C++ 中实现一个函数,该函数的(最终)类型应为 String -> String。比如说,是否可以使用完全相同的签名在 C++ 中重新实现以下函数?

import Data.Char
toUppers:: String -> String
toUppers s = map toUpper s

特别是,我想避免在返回类型中出现 IO,因为对于这个简单的任务引入杂质(我指的是 IO monad)在逻辑上是不必要的。到目前为止,我见过的所有涉及 C 字符串的示例都涉及返回 IO 内容或 Ptr,它们无法转换回纯 String

我想这样做的原因是我的印象是 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 的困惑委托(delegate)给 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]);
}

关于string - 如何在 Haskell 中编写纯字符串到字符串函数 FFI 到 C++,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16888135/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com