Я хочу открыть файл в Haskell, но я хочу, чтобы функция верхнего уровня вызывалась из C (я хочу передать путь к файлу из C).
У меня возникли проблемы с преобразованием filepathCString в тип, на котором я могу использовать readFile.
Вот моя первая попытка, адаптирующая пример из документации:
{-# LANGUAGE ForeignFunctionInterface #-}
import Foreign.C.Types
import Foreign.C (CString, peekCString)
openFileDoStuff :: String -> IO Bool
openFileDoStuff filename = do
lines <- (fmap lines . readFile) filename
print lines
-- do stuff with lines
return True
openFilepathHs :: CString -> IO Bool
openFilepathHs cstr = openFileDoStuff (peekCString cstr)
foreign export ccall openFilepathHs :: CString -> IO Bool
Я получаю сообщение об ошибке компилятора при передаче (peekCString cstr) в openFileDoStuff:
• Couldn't match type: IO String
with: [Char]
Если я изменю подпись своей функции на openFileDoStuff :: IO String -> IO Bool, я не смогу использовать параметр filename в вызове readFile:
• Couldn't match type: IO String
with: [Char]
Если это не совсем понятно, я новичок в Haskell. Я знаю, что нет способа преобразовать IO String -> String, но должен быть способ использовать тип CString.





Мне нужно было запуститьIO String и привязать его к переменной:
{-# LANGUAGE ForeignFunctionInterface #-}
import Foreign.C.Types
import Foreign.C (CString, peekCString)
openFileDoStuff :: IO String -> IO Bool
openFileDoStuff filename = do
filenameString <- filename
lines <- (fmap lines . readFile) filenameString
print lines
-- do stuff with lines
return True
openFilepathHs :: CString -> IO Bool
openFilepathHs cstr = openFileDoStuff (peekCString cstr)
foreign export ccall openFilepathHs :: CString -> IO Bool
Используйте >>= для объединения действий ввода-вывода.
openFilepathHs cstr = peekCString cstr >>= openFileDoStuff
На самом деле, этот шаблон передачи части данных через последовательные преобразования ввода-вывода настолько распространен, что у него есть стандартный комбинатор для сокращения.
openFilepathHs = peekCString >=> openFileDoStuff
Вы также можете использовать синтаксис do, чтобы скрыть вызовы >>=, но лично мне, как новичку, было очень трудно понять синтаксис do, прежде чем я понял, как самому совершать вызовы >>=.
openFilepathHs cstr = do
cstrContents <- peekCString cstr
openFileDoStuff cstrContents
Очень необычно принимать
IOдействия в качестве аргументов. Для этого есть несколько причин, таких как обработка исключений, запуск потоков и некоторые другие, но в подавляющем большинстве случаев принимая чистый аргумент (и ожидая, что вызывающая сторона «выполнит» любые действия, необходимые для создания этого чистого значение) - это путь.