如何从 Haskell 调用 C++ Setters 和 Getters
How to Call C++ Setters & Getters from Haskell
我知道如何从 Haskell 调用纯 C++ 函数,但想知道如何让 GHC 接受有副作用的函数。
我希望 Haskell 具有对 C++ 链表的只读访问权限,以及对 C++ 变量的独占写入访问权限。例如:
class node {
// Some other class makes a linked list out of these
int x;
node* previous;
node* next;
}
class myHaskellInterface {
node* presentLocation; // C++ decides what is regarded as current location
int getVal() {
// Haskell calls this to get information from C++
return presentLocation->x;
}
int haskellResults; // Store Haskell output here
void setVal(int x) {
// Haskell calls this to pass information back
haskellResults = x;
}
};
尽管 getVal() 没有副作用,但它是 class 的一部分,显然有副作用,所以我不清楚是否需要偷偷摸摸的技巧才能让 GHC 接受它.
setVal(int) 明明有副作用,那怎么让GHC不care呢?
请注意,副作用的产生不是问题。重要的是 "impure" 与 "pure" 函数。虽然 getVal
不会 引起 副作用,但它 依赖于 副作用来产生一个值,因为它参考 presentLocation
.换句话说,它是一个不纯的函数。
Haskell无论是纯的还是非纯的都可以调用外部函数,只需要给它们适当的签名即可。必须为非纯函数指定 IO a
return 类型。可以为纯函数赋予非 IO
return 类型。 (当然,你 也可以 给一个纯函数一个 IO
return 类型,但你没有必要,所以通常也不会。)
例如,假设我们有简单的 C++ "interface":
int value = 0; // Haskell code sets value directly
extern "C" int getValue() { return value; } // and gets it with this
如果我们错误地尝试将getValue
导入为纯函数:
foreign import ccall "interface.cc &value" valuePtr :: Ptr CInt
foreign import ccall "interface.cc getValue" getValue :: CInt -- **NO NO NO!!!**
然后像这样测试它:
main :: IO ()
main = do
print getValue
poke valuePtr 5
print getValue
我们得到不正确的输出:
0
0
相反,我们需要给 getValue
一个类型 IO CInt
:
foreign import ccall "interface.cc getValue" getValue :: IO CInt
对程序的其余部分进行适当修改:
import Foreign
import Foreign.C
foreign import ccall "interface.cc &value" valuePtr :: Ptr CInt
foreign import ccall "interface.cc getValue" getValue :: IO CInt
main :: IO ()
main = do
print =<< getValue
poke valuePtr 5
print =<< getValue
输出符合预期:
0
5
请注意,只有 return 值才应被赋予 IO
类型。如果我们添加一个带参数的不纯函数,例如:
extern "C" int getMultValue(int scale) { return value*scale; }
那么你会使用:
foreign import ccall "interface.cc getMultValue" getMultValue :: CInt -> IO CInt
完整节目:
// interface.cc
int value = 0;
extern "C" int getValue() { return value; }
extern "C" int getMultValue(int scale) { return value*scale; }
-- Main.hs
import Foreign
import Foreign.C
foreign import ccall "interface.cc &value" valuePtr :: Ptr CInt
foreign import ccall "interface.cc getValue" getValue :: IO CInt
foreign import ccall "interface.cc getMultValue" getMultValue :: CInt -> IO CInt
main :: IO ()
main = do
print =<< getValue
poke valuePtr 5
print =<< getValue
print =<< getMultValue 5
请注意,当所讨论的函数或变量实际上是方法/实例变量时,事情会变得有点复杂。 Haskell 不直接支持使用 C++ 对象,因此您需要构建某种 extern "C"
接口并将对象指针作为显式参数传递。如果您 运行 在您的设计中进一步遇到麻烦,也许 post 其他问题,我们会尽力提供帮助。
我知道如何从 Haskell 调用纯 C++ 函数,但想知道如何让 GHC 接受有副作用的函数。
我希望 Haskell 具有对 C++ 链表的只读访问权限,以及对 C++ 变量的独占写入访问权限。例如:
class node {
// Some other class makes a linked list out of these
int x;
node* previous;
node* next;
}
class myHaskellInterface {
node* presentLocation; // C++ decides what is regarded as current location
int getVal() {
// Haskell calls this to get information from C++
return presentLocation->x;
}
int haskellResults; // Store Haskell output here
void setVal(int x) {
// Haskell calls this to pass information back
haskellResults = x;
}
};
尽管 getVal() 没有副作用,但它是 class 的一部分,显然有副作用,所以我不清楚是否需要偷偷摸摸的技巧才能让 GHC 接受它.
setVal(int) 明明有副作用,那怎么让GHC不care呢?
请注意,副作用的产生不是问题。重要的是 "impure" 与 "pure" 函数。虽然 getVal
不会 引起 副作用,但它 依赖于 副作用来产生一个值,因为它参考 presentLocation
.换句话说,它是一个不纯的函数。
Haskell无论是纯的还是非纯的都可以调用外部函数,只需要给它们适当的签名即可。必须为非纯函数指定 IO a
return 类型。可以为纯函数赋予非 IO
return 类型。 (当然,你 也可以 给一个纯函数一个 IO
return 类型,但你没有必要,所以通常也不会。)
例如,假设我们有简单的 C++ "interface":
int value = 0; // Haskell code sets value directly
extern "C" int getValue() { return value; } // and gets it with this
如果我们错误地尝试将getValue
导入为纯函数:
foreign import ccall "interface.cc &value" valuePtr :: Ptr CInt
foreign import ccall "interface.cc getValue" getValue :: CInt -- **NO NO NO!!!**
然后像这样测试它:
main :: IO ()
main = do
print getValue
poke valuePtr 5
print getValue
我们得到不正确的输出:
0
0
相反,我们需要给 getValue
一个类型 IO CInt
:
foreign import ccall "interface.cc getValue" getValue :: IO CInt
对程序的其余部分进行适当修改:
import Foreign
import Foreign.C
foreign import ccall "interface.cc &value" valuePtr :: Ptr CInt
foreign import ccall "interface.cc getValue" getValue :: IO CInt
main :: IO ()
main = do
print =<< getValue
poke valuePtr 5
print =<< getValue
输出符合预期:
0
5
请注意,只有 return 值才应被赋予 IO
类型。如果我们添加一个带参数的不纯函数,例如:
extern "C" int getMultValue(int scale) { return value*scale; }
那么你会使用:
foreign import ccall "interface.cc getMultValue" getMultValue :: CInt -> IO CInt
完整节目:
// interface.cc
int value = 0;
extern "C" int getValue() { return value; }
extern "C" int getMultValue(int scale) { return value*scale; }
-- Main.hs
import Foreign
import Foreign.C
foreign import ccall "interface.cc &value" valuePtr :: Ptr CInt
foreign import ccall "interface.cc getValue" getValue :: IO CInt
foreign import ccall "interface.cc getMultValue" getMultValue :: CInt -> IO CInt
main :: IO ()
main = do
print =<< getValue
poke valuePtr 5
print =<< getValue
print =<< getMultValue 5
请注意,当所讨论的函数或变量实际上是方法/实例变量时,事情会变得有点复杂。 Haskell 不直接支持使用 C++ 对象,因此您需要构建某种 extern "C"
接口并将对象指针作为显式参数传递。如果您 运行 在您的设计中进一步遇到麻烦,也许 post 其他问题,我们会尽力提供帮助。