3 ms·
There is a simple way to implement a dense computational kernel in haskell: write it in C++ and call it using the foreign function interface. Seriously, this i
by conistonwater 12y ago
There is a simple way to implement a dense computational kernel in haskell: write it in C++ and call it using the foreign function interface.
Seriously, this is not (as I understand it) a problem that Haskell is designed to solve. Haskell is expressive, functional, lazy, etc., and that is all great, but if you care about actual instructions that get executed on the cpu, haskell doesn't care, and that's supposed to be like that. For me, writing performant haskell always descends into a game of figuring out why the compiler didn't unbox something or other, or why it didn't understand that a certain variable can be made strict.
My advice would be: if performance is really the main thing you need, study c++ and learn how to write clean code in c++. [0] And in the end, you can always call c++ functions from haskell.
If you really need to use haskell, then just learn in detail how the runtime and the compiler work, so that their output is predictable.
The chains of c++ is what makes sure that c++ code can be mapped almost directly to machine-level instructions.
[0] Maybe you already know c++ better than I do, in which case ignore me.
- fsloth 12y agoThanks. This was what I was expecting. Although, I was hoping FFI was not the answer http://rwmj.wordpress.com/2011/09/21/which-foreign-function-interface-is-the-best/ http://rwmj.wordpress.com/2011/09/21/which-foreign-function-... Richard Jones is fairly erudite in the art and industry (one of the authors of http://gchandbook.org/ http://gchandbook.org/ and quite proficient around various programming languages in general) and if he says Haskell FFI is painful to work with I get a really bad feeling. I was hoping the answer would have been "There is this stream computation library that is really neat and just works...".
- tome 12y agoThat's strange to read. The Haskell community believes GHC's FFI is very good. Perhaps things have changed in the last three years. (I've never used the FFI so cannot respond directly.)
- conistonwater 12y ago> There is this stream computation library Sometimes Haskell allows you to easily implement algorithms that would be, comparatively, much more painful to write in c++. There are stream fusion libraries, and it's important to know them. You can do a lot with plain Haskell before you need to start worrying about CPU instructions. Things like linear algebra, matrix multiplication kernels are exceptions. > Haskell FFI is painful to work That link is three years old, and I think I disagree with some of things he says. I agree that haskell ffi is poorly documented. But he also says it is "deeply strange". Without using any extra tools, I would say it is a little laborious, but conceptually very simple. He also says he couldn't figure out how to return anything other than integers. Think about it this way. Haskell makes no mention of how its objects are laid out in memory. If you pass a native Haskell object (a boxed int, or a struct) to C, C code will not ever be able to unwrap it without making guesses about memory layout. What Haskell expects you to do is to do this yourself: if a structure consists of an integer and a double, you define (yourself) a function that takes a pointer, and lays out the integer and the double in the memory as your C code would expect to find them there. Then every FFI call takes the form 1. Allocate a chunk of memory. 2. Store your Haskell object into that memory, using your layout. This is what the `poke` function does. 3. Pass the pointer to a C function. 4. C function reads and writes to that chunk of memory. 5. When C function returns, read from the memory and pack the results into a Haskell object. This is the `peek` function. 5a. Quite often a C function would return a success code anyway, and the actual return value will be written to a pointer passed to the C function. This is really common. 6. Deallocate the chunk of memory. 6a. Notice that no assumptions were made about internal object layout, except that you have to know what layout the corresponding C structure is expected to have. This might also be the reason why it's unintuitive how to return complicated objects from C. The complicated objects need to be explicitly unpacked and stored into a Haskell object. There are tools that automate this process, but the tool-less FFI is straightforward once you figure it out. Here is the layout GHC actually uses: https://ghc.haskell.org/trac/ghc/wiki/Commentary/Rts/Storage/HeapObjects https://ghc.haskell.org/trac/ghc/wiki/Commentary/Rts/Storage... This is maybe a bit unintuitive, but it makes sense to me.
- fsloth 12y agoThanks for your overview. I had not done yet a deep analysis of the FFI myself, your summary clarified things.