0

Когда я читал документацию SDL в haskell, я обнаружил, что некоторые функции неизбежно изменяют его вход. Например, blitSurface имеет поверхность назначения как входную, но обновляется внутри функции. Теперь, обобщая проблему, если у меня есть функция f :: a -> IO a, она нарушает состав, если я изменяю a внутри функции? Что насчет f :: IO a -> IO a? Что насчет a -> IO()? А как насчет IO a -> IO()?Разбивает ли он композицию для изменения ввода в Haskell?

Учитывая, что blitSurface на самом деле является чужой функцией, а создание новой поверхности каждого кадра не очень эффективно, эти функции трудно избежать. Будут ли такие функции вызывать проблемы в более широких масштабах? Например, с помощью fModifySurface :: Surface -> IO(), который делает разрушительное обновление в качестве примера:

main = do 
    w <- ... -- The window surface 
    -- Do something here 
    s <- someFuncGetSurface -- We get a surface here 
    fModifySurface s -- Destructively update s 
    blitSurface ...... -- Ignore the actual API, but destructively updates w 

Существует ли какая-либо неожиданная семантика в коде выше? Если да, то каков наилучший способ использовать внешние функции, которые меняют ввод?

+1

Строго говоря, это не «функции». –

+0

ОК, «функции» в императивном смысле. –

+1

Пока все внешние функции возвращают 'IO SomeType', фундаментальное свойство не должно быть нарушено. Ваш случай сильно отличается от того, что вы звоните, например. 'writeIORef' для обновления изменяемой переменной? Последний «безопасен», даже если его можно злоупотреблять, чтобы написать унииоматический код. – chi

ответ

5

Я наблюдаю, что f a b и flip f b a являются бета-эквивалентными условиями. С другой стороны, простая версия IO, а именно, f <$> a <*> b и flip f <$> b <*> a, безусловно, не является бета-эквивалентной; и даже используя эквивалентность от "Tackling the Awkward Squad", что делает еще много эквивалентных действий IO, эти два условия не эквивалентны.

На высоком уровне это означает, что если вы докажете что-то о поведении чистых терминов, вы можете повторно использовать это доказательство, даже если чистое вычисление используется как часть более крупной программы. С другой стороны, не существует соответствующего способа равномерного поднятия локального доказательства о терминах IO в доказательство относительно более крупной программы на основе IO; если вы хотите сделать это, вы должны вызывать около глобальных объектов недвижимости по специфическим IO действиям, которые планируете использовать вместе.

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

Однако ни одно из этих обсуждений не относится к FFI или к функциям, действие которых IO обновляет значения, на которые ссылается один из их входов. blitSurface не хуже и не лучше в этом отношении, чем в основном любой из «бита sin», который мы бросаем в IO. Императивные программы просто не являются композиционными в том же смысле, что и чистые.

+0

Итак, теперь я просто держу один чрезвычайно тонкий слой 'IO' для легкого ручного управления. –

+0

Некоторое упоминание об индексированных монадах и системах эффектов может быть уместным. – dfeuer