Привет, RSDN.
Будь добр, помоги пожалуйста с FFI Haskell (GHC), если у тебя есть возможность.
Проблема в следующем: я умею в Хаскеле генерить строки по заданному регексу — генексы. Получаю ленивый список строк, который, в принципе, может быть бесконечным. Этот список строк хотелось бы использовать в программе на C. Поэтому хотелось передать в C вычисление, сделанное на Хаскеле, и итеративно отъедать от него строки по мере надобности. Прочитал кучу документации по FFI, но все равно ни как не могу сообразить. Написал в Хаскель-бегинерс, но тоже не дали ответ. Может быть ты поможешь?
Хотелось бы следующего:
COMPUTATION c = open("rege\x");
while(need_next()) {
printf(next( c ));
}
close( c );
С уважением, Александр.
Здравствуйте, alexander.vladislav.popov, Вы писали:
AVP>Привет, RSDN.
AVP>Будь добр, помоги пожалуйста с FFI Haskell (GHC), если у тебя есть возможность.
AVP>Проблема в следующем: я умею в Хаскеле генерить строки по заданному регексу — генексы. Получаю ленивый список строк, который, в принципе, может быть бесконечным. Этот список строк хотелось бы использовать в программе на C. Поэтому хотелось передать в C вычисление, сделанное на Хаскеле, и итеративно отъедать от него строки по мере надобности. Прочитал кучу документации по FFI, но все равно ни как не могу сообразить. Написал в Хаскель-бегинерс, но тоже не дали ответ. Может быть ты поможешь?
AVP>Хотелось бы следующего:
AVP>AVP>COMPUTATION c = open("rege\x");
AVP>while(need_next()) {
AVP> printf(next( c ));
AVP>}
AVP>close( c );
AVP>
AVP>С уважением, Александр.
Что именно вызывает проблемы?
Экспортируйте функции (пишу на память, могу соврать, лучше точнее посмотреть в доках)
foreign export ccall open :: CString -> IO (Ptr ())
foreign export ccall need_next :: Ptr () -> IO Bool
foreign export ccall next :: Ptr () -> IO CString
В Ptr () запихиваете любые Haskell-данные, получив из них StablePtr a и закастив к Ptr ().
Строки конвертируете через newCString, peekCString, peekCString.
Придётся, правда, позаботиться об освобождении самому, написав какую-нибудь close, а строки не самому выделять, а получать и заполнять буффер.
Всё, что нужно, можно смотреть
здесь в модулях Foreign.
Здравствуйте, VoidEx, Вы писали:
VE>Экспортируйте функции (пишу на память, могу соврать, лучше точнее посмотреть в доках)
VE>VE>foreign export ccall open :: CString -> IO (Ptr ())
VE>foreign export ccall need_next :: Ptr () -> IO Bool
VE>foreign export ccall next :: Ptr () -> IO CString
VE>
VE>В Ptr () запихиваете любые Haskell-данные, получив из них StablePtr a и закастив к Ptr ().
VE>Строки конвертируете через newCString, peekCString, peekCString.
VE>Придётся, правда, позаботиться об освобождении самому, написав какую-нибудь close, а строки не самому выделять, а получать и заполнять буффер.
VE>Всё, что нужно, можно смотреть здесь в модулях Foreign.
Вот наивная, но рабочая версия. Добавьте критики.
-- genexlib.hs
{-# LANGUAGE BangPatterns, ForeignFunctionInterface #-}
module GenexLib where
import Regex.Genex
import System.IO
import System.Environment
import Foreign
import Foreign.Ptr
import Foreign.C.String
import Foreign.C.Types
import Foreign.Marshal.Alloc
data CLazyList a = Empty | CLL !a [a]
instance (Show a) => Show (CLazyList a) where
show Empty = "Empty"
show (CLL x xs) = show x ++ ":.."
next'pure :: CLazyList a -> CLazyList a
next'pure (CLL _ []) = Empty
next'pure (CLL _ (x:xs)) = CLL x xs
fromList :: [a] -> CLazyList a
fromList [] = Empty
fromList (x:xs) = CLL x xs
open'pure :: [String] -> CLazyList String
open'pure = fromList . genexPure
foreign export ccall open :: CString -> IO (Ptr ())
open cs = do
s <- peekCString cs
sptr <- newStablePtr $ open'pure [s]
return $ castStablePtrToPtr sptr
foreign export ccall need_next :: Ptr () -> IO (Ptr ())
need_next ptr = do
if ptr == nullPtr
then
return nullPtr
else do
let stable = castPtrToStablePtr ptr
lazylist <- deRefStablePtr stable
let tail = next'pure lazylist
case tail of
Empty -> do
freeStablePtr stable
return nullPtr
_ -> do
new'stable <- newStablePtr tail
freeStablePtr stable
return $ castStablePtrToPtr new'stable
foreign export ccall next :: Ptr () -> CString -> CInt -> IO CString
next ptr str len = do
if ptr == nullPtr
then
return nullPtr
else do
let stable = castPtrToStablePtr ptr
lazylist <- deRefStablePtr stable
case lazylist of
Empty -> return str
CLL x xs -> do
c <- newCString x
copyArray str c $ 1 + length x
free c
return str
foreign export ccall close :: Ptr () -> IO ()
close ptr = do
if ptr == nullPtr then return ()
else do
let stable = castPtrToStablePtr ptr
freeStablePtr stable
return ()
// genex.c
#include <stdio.h>
#include <stdlib.h>
#include "genexlib_stub.h"
int main(int argc, char *argv[]) {
if(argc < 2) {
printf("Usage: genex <regex>");
exit(0);
}
hs_init(&argc, &argv);
void *c = open(argv[1]);
int i = 0;
while(c = need_next(c)) {
char buf[256];
buf[0] = 0;
printf("iter %d: ", ++i);
printf("%s\n", next( c, buf, 256 ));
}
close( c );
hs_exit();
}
компилировать
>ghc -c genexlib.hs
>ghc -package regex-genex genex.c genexlib.o genexlib_stub.o -o genex