Closed
Description
Currently, C's char
types can be marshalled to and from Integral
types via the default marshaller fromIntegral
. Unfortunately, this makes it difficult to use Haskell's own Char
type alongside C's, since Char
is not an instance of Integral
. For example,
/* foo.h */
#ifndef FOO_H
#define FOO_H
char identichar(char c);
unsigned char identiuchar(unsigned char c);
signed char identischar(signed char c);
#endif
/* foo.c */
#include "foo.h"
char identichar(char c) {
return c;
}
unsigned char identiuchar(unsigned char c) {
return c;
}
signed char identischar(signed char c) {
return c;
}
-- Main.chs
{-# LANGUAGE ForeignFunctionInterface #-}
module Main where
import Foreign.C.String
#include "foo.h"
{#fun pure identichar as ^ { `Char' } -> `Char' #}
{#fun pure identiuchar as ^ { `Char' } -> `Char' #}
{#fun pure identischar as ^ { `Char' } -> `Char' #}
main :: IO ()
main = print $ map ($ 'A') [identichar, identiuchar, identischar]
Preprocessing this with c2hs
reveals this:
c2hs: Errors during expansion of binding hooks:
./Main.chs:9: (column 43) [ERROR] >>> Missing "out" marshaller!
There is no default marshaller for this combination of Haskell and C type:
Haskell type: Char
C type : CSChar
./Main.chs:8: (column 43) [ERROR] >>> Missing "out" marshaller!
There is no default marshaller for this combination of Haskell and C type:
Haskell type: Char
C type : CUChar
./Main.chs:7: (column 43) [ERROR] >>> Missing "out" marshaller!
There is no default marshaller for this combination of Haskell and C type:
Haskell type: Char
C type : CChar
So one must manually provide out marshallers:
import Foreign.C.String
import Foreign.C.Types
{#fun pure identichar as ^ { `Char' } -> `Char' castCCharToChar #}
{#fun pure identiuchar as ^ { `Char' } -> `Char' castCUCharToChar #}
{#fun pure identischar as ^ { `Char' } -> `Char' castCSCharToChar #}
This, in turn, reveals the lack of in marshallers for Char
:
c2hs: Errors during expansion of binding hooks:
./Main.chs:11: (column 31) [ERROR] >>> Missing "in" marshaller!
There is no default marshaller for this combination of Haskell and C type:
Haskell type: Char
C type : CSChar
./Main.chs:10: (column 31) [ERROR] >>> Missing "in" marshaller!
There is no default marshaller for this combination of Haskell and C type:
Haskell type: Char
C type : CUChar
./Main.chs:9: (column 31) [ERROR] >>> Missing "in" marshaller!
There is no default marshaller for this combination of Haskell and C type:
Haskell type: Char
C type : CChar
So the final workaround ends up being pretty verbose:
{#fun pure identichar as ^ { castCharToCChar `Char' } -> `Char' castCCharToChar #}
{#fun pure identiuchar as ^ { castCharToCUChar `Char' } -> `Char' castCUCharToChar #}
{#fun pure identischar as ^ { castCharToCSChar `Char' } -> `Char' castCSCharToChar #}
Is it possible to have these marshallers be the defaults for Haskell's Char
?