I know how to call pure C++ functions from Haskell, but wondering how to get GHC to accept functions that have side effects.
I want Haskell to have read-only access to a C++ linked list, and exclusive write access to a C++ variable. For example:
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;
}
};
Even though getVal() doesn't have side effects, it is part of a class that obviously has side effects, so it's not clear to me whether sneaky tricks are required to get GHC to accept it.
setVal(int) clearly has side effects, so how do you make GHC not care?
Note that the production of side effects isn't the issue. It's "impure" versus "pure" functions that are important. While
getVal
doesn't cause side effects, it relies on side effects to produce a value because it consultspresentLocation
. In other words, it's an impure function.Haskell can call foreign functions whether they are pure or impure, you just need to give them appropriate signatures. An impure function must be given an
IO a
return type. A pure function can be given a non-IO
return type. (Of course, you could give a pure function anIO
return type, too, but you don't have to and so usually wouldn't.)For example, suppose we have the simple C++ "interface":
If we incorrectly try to import
getValue
as a pure function:and test it like so:
we get incorrect output:
Instead, we need to give
getValue
a typeIO CInt
:With appropriate modifications to the rest of the program:
the output is as expected:
Note that it's only the return value that should be given an
IO
type. If we add an impure function that takes arguments, like:then you'd use:
The full programs:
Note that things will get a little more complicated when the functions or variables in question are actually methods / instance variables. Haskell doesn't directly support working with C++ objects, so you need to build some kind of
extern "C"
interface and pass object pointers as explicit arguments. If you run into trouble a little further along in your design, maybe post additional questions and we'll try to help.