如何将Haskell FFI中的纯字符串到字符串函数写入C++; 我想通过Haskell FFI实现C++中的函数,它应该具有(最终)类型的 String >字符串< /代码>。那么,在C++中,可以用相同的签名来实现 >下面的函数吗?< /P> import Data.Char toUppers:: String -> String toUppers s = map toUpper s

如何将Haskell FFI中的纯字符串到字符串函数写入C++; 我想通过Haskell FFI实现C++中的函数,它应该具有(最终)类型的 String >字符串< /代码>。那么,在C++中,可以用相同的签名来实现 >下面的函数吗?< /P> import Data.Char toUppers:: String -> String toUppers s = map toUpper s,string,haskell,ffi,purely-functional,String,Haskell,Ffi,Purely Functional,特别是,我希望避免在返回类型中使用IO,因为为这个简单任务引入杂质(我的意思是IO monad)在逻辑上是不必要的。到目前为止,我所看到的所有涉及C字符串的示例都涉及返回一个IO something或Ptr,该IO something或Ptr无法转换回纯字符串 我想这样做的原因是,我有一种印象,即编组与外国金融机构是混乱的。也许如果我能修复上面的最简单的情况(除了原始类型,如int),那么我就可以在C++上做任何我想要的数据解析,这应该是容易的。 与我希望在编组到/从字符串之间进行的计算相比,解

特别是,我希望避免在返回类型中使用IO,因为为这个简单任务引入杂质(我的意思是IO monad)在逻辑上是不必要的。到目前为止,我所看到的所有涉及C字符串的示例都涉及返回一个IO something或Ptr,该IO something或Ptr无法转换回纯
字符串

我想这样做的原因是,我有一种印象,即编组与外国金融机构是混乱的。也许如果我能修复上面的最简单的情况(除了原始类型,如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
在这里,我们使用
with cstring
将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++函数,它们适合上述导入:

#包括
外部“C”型空塔器(字符*s){
对于(;*s;s++)*s=toupper(*s);
}
外部“C”void touppers2(int l,char*s,char*t){
对于(inti=0;i
您能提供一些您想要完成的更多细节吗?从RWH“但是,如果我们知道C代码是纯类型的,为什么不在导入声明中为它指定一个纯类型来声明它呢?”?因为我们必须为C函数分配本地内存,这必须在IO monad中完成,因为这是一个本地副作用。这些效果不会逃脱围绕外部调用的代码,但是,当我们使用“unSufPrimoIO”来重新介绍C++时,C++:“更具体地说,我想做简单的计算(C++),比如在C++中求解线性方程组。这个解决方案需要用C++来完成。这就是为什么我想使用字符串或等价物。(最终)在FFI上传输数据。所以我在C++世界中寻找一个编组字符串或等价物的例子,不引入IO。BTW,HMLAST在我使用Windows /MIW时不适用。所以我认为最可靠的解决方案是像上面所描述的那样设计一个工作FFI源。o将整数或双精度数组(向量)从haskell传输到C/C++并返回,其签名与传输C字符不同。haskell中的字符串与C字符[]完全不同。感谢您的回答。您能演示如何在C/C++端转换为大写吗?我想“重新实现”“触发器在C++中的作用(如在问题中),因为我真正感兴趣的是C++在Haskell中解析字符串时的工作,做一些计算(在这种情况下,ToupPress作为一个简单的例子)。,并将结果以字符串形式传递回Haskell。非常感谢。当然,给你-没有什么太壮观或精致的东西,但它应该能让你继续。这取决于“解析”的含义,您应该尝试一下Haskell解析库,如
parsec
attoparsec
。Haskell在这方面可以非常快,只要您对字符串使用
ByteString
Text
。谢谢。顺便问一句,以上两个函数是懒惰的还是它们与(map toUpper)之间有什么区别,而不是效率?也就是说,用FFI实现替换(map toUpper)以获得相同的行为是否安全?此外,我尝试在windows/mingw上加载此功能。“ghc—使strFFI.hs touppers.cpp”起作用,但“ghci strFFI.hs touppers.o”或“ghci strFFI.hs-ltoppers”不起作用。ghci说:最后一个链接…ghc.exe:touppers.o:未知符号“\uu imp\u toupper”。有指针吗?没有,它们一点也不懒惰-在无限列表上使用新的
toupper
不会终止。错误听起来像是缺少一个库,可能添加了“-lstdc++”帮助?