LINUX.ORG.RU

[Haskell] [FFI] Оформить IO Функцию

 ,


0

2

Здравствуйте, у меня есть вот такой код на С

#include <stdio.h>

void hello()
{
	printf("Hello");
}

int ret3()
{
	return 3;
}
И я хочу импортировать эти функции в Хаскель
{-# INCLUDE "hello.c" #-}
{-# LANGUAGE ForeignFunctionInterface #-}
module Example(c_hello,c_ret) where
import Foreign.C
import Foreign.C.String

foreign import ccall unsafe "hello" c_hello :: IO()
foreign import ccall unsafe "ret3" c_ret :: СInt
Если вызывать c_ret, то все происходит правильно, а если вызывать c_hello, то вывод откладывается до выхода из интерпретатора. Я неправильно оформляю IO функцию?

★★★★★

Ты все делаешь правильно. Думаю, что проблема(строго говоря, проблемы то и нет) с построчной буферизацией stdout. Попробуй добавить \n в конце Hello

Waterlaz ★★★★★
()

{-# INCLUDE

Как там в 2006?

anonymous
()

Можно попробовать вручную сбрасывать буфер c-потоков, если не хочется менять сишный код:

hello.c:

#include "hello.h"
#include <stdio.h>

void hello()
{
    printf("Hello");
}

int ret3()
{
    return 3;
}

void flush()
{
    fflush(stdout);
}

Example.hs:

{-# LANGUAGE ForeignFunctionInterface #-}
module Example (hello, ret, cFlush) where

import Foreign
import Foreign.C
import Foreign.Ptr

foreign import ccall unsafe "hello.h hello" hello :: IO ()
foreign import ccall unsafe "hello.h ret3" c_ret :: CInt
foreign import ccall unsafe "hello.h flush" cFlush :: IO ()

ret :: Int
ret = fromIntegral c_ret

Main.hs:

import Example

main = hello >> cFlush >> putChar '\n' >> print ret

hello.h, понятное дело, содержит прототипы функций

theNamelessOne ★★★★★
()
Ответ на: комментарий от redixin

буферизация тут не при чем. соль в ленивости хацкеля

ну расскажи по-подробнее про ленивость

max@nix ~ % cat hello.c 
#include <stdio.h>

void hello()
{
        printf("Hello\n");
}

int ret3()
{
        return 3;
}

max@nix ~ % cat hello.h
void hello();
int ret3();
max@nix ~ % cat foo.hs 
{-# LANGUAGE ForeignFunctionInterface #-}

import Foreign
import Foreign.C
import Foreign.Ptr

foreign import ccall unsafe "hello.h hello" hello :: IO ()
foreign import ccall unsafe "hello.h ret3" c_ret :: CInt

ret :: Int
ret = fromIntegral c_ret

main = do hello
          print ret

max@nix ~ % ghc --make foo.hs hello.c
Linking foo ...
max@nix ~ % ./foo                    
Hello
3
Begemoth ★★★★★
()

вывод откладывается до выхода из интерпретатора

Что можно сделать:

  • fflush(stdout) на сишной стороне каждый раз.
  • Импортировать fflush(stdout) (или из stdio.h в виде c_fflush - обычно так и делают) и вызывать его со стороны хаскеля каждый раз.
  • Импортировать setvbuf(stdout, (char*)NULL, _IONBF, 0) (или саму setvbuf оформить) и вызвать со стороны хаскеля единожды, ещё можно импортировать setlinebuf(stdout) (саму setlinebuf) и вызывать для восстановления буферизации.
quasimoto ★★★★
()
Ответ на: комментарий от redixin
main()
{
        printf("1\n");
        sleep(10);
}
main()
{
        printf("1");
        sleep(10);
}

http://stackoverflow.com/questions/3723795/is-stdout-line-buffered-unbuffered...

В данном случае сишные streams реализованные в libc (с line buffering) и IO в RTS хаскеля (управляемые IO manager) работают независимо - предпочтительный способ буферизации нужно выбирать и там и там, синхронизировать с помощью двух разных (независимых) вызовов flush.

quasimoto ★★★★
()
Ответ на: комментарий от Begemoth

по описанию ТС, у него была классическая проблема с ленивостью. проблемы с IO у хаскеля известны даже за пределами хаскеля.

redixin ★★★★
()
Ответ на: комментарий от quasimoto

да знаю я, просто не обратил внимание на отсутсвие \n, а обратил внимание на слово «хаскель» и «вывод осуществляется только после выхода»

redixin ★★★★
()
Ответ на: комментарий от redixin

И как связаны «ленивость» и «вывод осуществляется только после выхода»? Завязывай валить на хаскель свое невежество.

anonymous
()

Спасибо всем

Aswed ★★★★★
() автор топика
Ответ на: комментарий от redixin

То есть: main = print 1 >> sleep 10 >> print 2 — напечатает «1» только при выходе?

// другой анонимус, в хаскеле не разбираюсь, просто интересно

anonymous
()
Ответ на: комментарий от anonymous

скорее всего нет. а вот если print 1 запилить в функцию, вызвать ее, и сделать слип 1, то скорее всего напечатает только при выходе.

redixin ★★★★
()
Ответ на: комментарий от anonymous

Нет, конечно. Напечатает 1, подождет 10 секунд, напечатает 2.

anonymous
()
Ответ на: комментарий от redixin

я не шарю в хацкеле

Зачем тогда отвечаешь глупости про ленивость?

Waterlaz ★★★★★
()
Ответ на: комментарий от redixin

скорее всего нет. а вот если print 1 запилить в функцию, вызвать ее, и сделать слип 1, то скорее всего напечатает только при выходе.

Бред от первого до последнего слова.

Begemoth ★★★★★
()
Ответ на: комментарий от redixin

проблемы с IO у хаскеля известны даже за пределами хаскеля.

Не «даже», а «только».

Miguel ★★★★★
()
Ответ на: комментарий от anonymous

То есть: main = print 1 >> sleep 10 >> print 2 — напечатает «1» только при выходе?

Если так:

import Control.Concurrent
main = print 1 >> threadDelay 10000000 >> print 2

то напечатает 1, подождёт, напечатает 2, потому что print добавляет к текстовому представлению, полученному с помощью инстанса Show, символ конца строки.

Если так (и с line buffering):

import Control.Concurrent
main = putStr "1" >> threadDelay 10000000 >> putStrLn "2"

то подождёт, потом напишет 1 и 2. Ну, короче, так же как в си, и в любом другом языке с буфферизированными потоками IO.

quasimoto ★★★★
()
Ответ на: комментарий от anonymous

можно и System.Posix.Unistd.sleep

Но зачем? Control.Concurrent.threadDelay платформо-независим и связан с планировщиком, который у GHC свой (правда, RT гарантий у него нет, только гарантия что delay будет _не меньше_ указанного значения в микросекундах).

quasimoto ★★★★
()
Ответ на: комментарий от redixin

какие то анонимусы безгамотные пошли, не знают ничего о ленивости и вводе-выводе в хаскеле. ужс

мда уж. это ты не знаешь ничего о ленивости и ио в хаскеле.

kyz
()
Ответ на: комментарий от redixin

скорее всего нет. а вот если print 1 запилить в функцию, вызвать ее, и сделать слип 1, то скорее всего напечатает только при выходе.

фиерично

kyz
()
Ответ на: комментарий от redixin

как можно так упорствовать в своём невежестве?

Prelude Data.Time Control.Concurrent> let k = getCurrentTime >>= print
(0.04 secs, 16840976 bytes)
Prelude Data.Time Control.Concurrent> getCurrentTime >>= print >> k >> threadDelay 10000 >> getCurrentTime >>= print
2012-04-09 21:08:57.355591 UTC
2012-04-09 21:08:57.355943 UTC
2012-04-09 21:08:57.366491 UTC
qnikst ★★★★★
()
Ответ на: комментарий от qnikst

а чего ж у меня getCurrentTime время кривое достаёт...

Это в UTC он показывает, для локального нужно Data.Time.LocalTime.getZonedTime.

quasimoto ★★★★
()
Ответ на: комментарий от qnikst

сначала просит уйти, потом что то спрашивает не по-русски.

забыл таблетки принять?

redixin ★★★★
()
Ответ на: комментарий от redixin
import System.Process

foo = print 1

main = foo >> system "sleep 1" >> print 2

И что б вы думали! печатает 1, ждет, печатает 2.

Aswed ★★★★★
() автор топика
Ответ на: комментарий от redixin

Здесь нет связывания дурик, do это лишь синтаксический сахар. Документацию по Хаскелю почитай, или книжку. Вообще почитай что-нибудь, что бы глупости не говорить.

Aswed ★★★★★
() автор топика
Ответ на: комментарий от redixin

А еще лучше приведи пример кода «без связывания», где лень работает не правильно, и что-то там выводиться не корректно, если конечно твои слова не пустые.

Aswed ★★★★★
() автор топика
Ответ на: комментарий от redixin

я так и не понял, что ты хочешь, объяснись, что по твоему значит «обернуть функцией» это цитата из твоих слов "[Haskell] [FFI] Оформить IO Функцию (комментарий) Если тебе не нравится let, то не обращай внимания, т.к. это был ghci.

import Control.Concurrent
f = print "123"

main = f  >> threadDelay 100000000 >> print "7"

печатает f сразу.

qnikst ★★★★★
()
Ответ на: комментарий от Aswed

«что-то там выводится» — пишется без мягкого знака

«неправильно» — пишется вместе (как и «некорректно»)

пожалуйста

redixin ★★★★
()
Ответ на: комментарий от qnikst
f = print "123"
d = threadDelay 100000

main = d + f

еще раз говорю: я хаскеля не знаю

если я правильно понял, то f и d могут выполниться вообще одновременно (в разных потоках например)

redixin ★★★★
()
Ответ на: комментарий от redixin

f и d могут выполниться вообще одновременно

Если под (+) подразумевается (>>), то не могут - выполнятся последовательно.

Статическая типизация обязывает типы совпадать - (+) :: Num t => t -> t -> t, так что сложить f и d, у которых типы IO (), никак не получится (если не написать instance Num (IO ())). Вот (>>) :: Monad m => m a -> m b -> m b подходит (так как существует instance Monad IO), это функция абстрактного интерфейса Monad, в случае m = IO конкретная функция (то есть реализация этого интерфейса для абстрактного типа IO) (>>) :: IO a -> IO b -> IO b имеет своей семантикой последовательное выполнение двух IO операций (то есть, гарантированно, сначала будет произведён один эффект, затем второй).

quasimoto ★★★★
()
Ответ на: комментарий от redixin

вот ты _действительно_ его не знаешь, поэтому пожалуйста не пиши фигню про ленивость.. Ты сильно путаешь понятия, нахватанные с разных сторон, и у тебя в голове каша, неправильная каша. Проблемы^W Особенности работы с IO в haskell есть, и они связаны с ленивостью основной библиотеки, но к данной проблеме они никак не относятся

Если ты хотел написать что-то вроде:

Prelude Control.Monad Control.Concurrent> liftM2 ((print .) . (+)) (print "123">>return 0)  (threadDelay 1000000 >> return 0) 
liftM2 ((print .) . (+)) (threadDelay 1000000 >> return 0) (print "123">>return 0)

то они выполнятся как надо сразу, если ты напишешь return (print «123») то оно выполнится, когда ты его явно вызовешь, но его тип будет m (IO ()), а не IO ().

да, если ты хочешь сделать

let k = liftM2 (+) (print "123">>return 0)  (threadDelay 1000000 >> return 0) 

то напечатается всё только когда ты вызовешь k, напечатается сразу, а не в конце программы, если ты k не зафорсишь, то не напечатается вобще. И тоже совершенно ортогонально проблеме.

qnikst ★★★★★
()
Ответ на: комментарий от quasimoto

скорее всего у redixin смесь информации о том, что в haskell lazy IO и с ним есть особенности (типа хранения лишних fs в каком-нибудь рекурсивном прочтении всех файлов в каталоге через hGetContents и их общей обработкой, или что при ленивой записи в файл может записаться всё когда рантайму это в голову придёт в итоге файл может быть заблокирован неопределенно догло) и то, что при ленивом связывании переменной создаётся Thunk, который вычисляется когда надо.

qnikst ★★★★★
()
Ответ на: комментарий от redixin

Этот код даже не скомпилится. Как ты себе вообще представляешь результат его работы? IO() + IO() что это за? как ты вообще представляешь тут операцию сложения? Не знаешь хаскеля - не пиши всякую хрень.

Aswed ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.