Открыть файл в haskell, передав путь к файлу в вызове C FFI (CString)

Я хочу открыть файл в 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.

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
96
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Мне нужно было запустить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

Очень необычно принимать IO действия в качестве аргументов. Для этого есть несколько причин, таких как обработка исключений, запуск потоков и некоторые другие, но в подавляющем большинстве случаев принимая чистый аргумент (и ожидая, что вызывающая сторона «выполнит» любые действия, необходимые для создания этого чистого значение) - это путь.

Daniel Wagner 07.12.2022 23:03
Ответ принят как подходящий

Используйте >>= для объединения действий ввода-вывода.

openFilepathHs cstr = peekCString cstr >>= openFileDoStuff

На самом деле, этот шаблон передачи части данных через последовательные преобразования ввода-вывода настолько распространен, что у него есть стандартный комбинатор для сокращения.

openFilepathHs = peekCString >=> openFileDoStuff

Вы также можете использовать синтаксис do, чтобы скрыть вызовы >>=, но лично мне, как новичку, было очень трудно понять синтаксис do, прежде чем я понял, как самому совершать вызовы >>=.

openFilepathHs cstr = do
    cstrContents <- peekCString cstr
    openFileDoStuff cstrContents

Другие вопросы по теме