Подтвердить что ты не робот

Разграничение монады IO

Приятно знать (по крайней мере, в Safe Haskell) из подписи, действительно ли что-то выполняет операции ввода-вывода, но IO включает в себя множество разных вещей - putStr, доступ к базе данных, удаление и запись в файлы, IORefs, и т.д.

Если я использую сигнатуры типа в качестве меры безопасности при запуске произвольного кода, может быть, я готов принять некоторые действия IO - putStr и, например, ilk, но не другие.

Есть ли способ определить ограниченную версию монады ввода-вывода с только подмножеством нормальных действий IO? Если да, то пример (с putStr, например) был бы очень желанным!

4b9b3361

Ответ 1

В качестве продолжения моего комментария вы можете реализовать его сами с чем-то вроде

class Monad io => Stdout io where
    putStr_ :: String -> io ()
    putStrLn_ :: String -> io ()
    print_ :: Show a => a -> io ()
    -- etc

instance Stdout IO where
    putStr_ = putStr
    putStrLn_ putStrLn
    print_ = print

myFunc :: Stdout io => io ()
myFunc = do
    val <- someAction
    print_ val
    let newVal = doSomething val
    print_ newVal

main :: IO ()
main = myFunc

Это не будет иметь абсолютно никаких накладных расходов во время выполнения, так как GHC оптимизирует эти типы классов, чтобы использовать только монаду IO, она расширяема, проста в написании и может быть легко скомбинирована с преобразованиями монады и классом MonadIO. Если у вас есть несколько классов, например класс Stdin с getLine_, getChar_ и т.д., Вы можете даже объединить эти классы с

class (Stdout io, Stdin io) => StdOutIn io where

myFunc :: StdOutIn io => io ()
myFunc = do
    val <- getLine_
    putStrLn_ $ "Echo: " ++ val

main :: IO ()
main = myFunc

Ответ 2

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