Ответ 1
На практике
Нет, это невозможно сделать, по крайней мере, не в значимом ключе.
Рассмотрим этот код Haskell
action :: Int -> IO String
action n = print n >> getLine
Сначала выполняется n
, печатает его (здесь выполняется IO), затем читает строку от пользователя.
Предположим, что мы имели гипотетический transform :: (a -> IO b) -> IO (a -> b)
. Затем, как мысленный эксперимент, рассмотрите:
action' :: IO (Int -> String)
action' = transform action
Вышеупомянутое должно сделать все IO заранее, прежде чем знать n
, а затем вернуть чистую функцию. Это не может быть эквивалентно приведенному выше коду.
Чтобы подчеркнуть эту точку, рассмотрим этот код бессмыслицы ниже:
test :: IO ()
test = do f <- action'
putStr "enter n"
n <- readLn
putStrLn (f n)
Волшебно, action'
должен заранее знать, что пользователь будет печатать дальше! Сеанс будет выглядеть как
42 (printed by action')
hello (typed by the user when getLine runs)
enter n
42 (typed by the user when readLn runs)
hello (printed by test)
Для этого требуется машина времени, поэтому это невозможно.
В теории
Нет, это невозможно. Аргумент похож на тот, который я дал на аналогичный вопрос.
Предположим противное transform :: forall m a b. Monad m => (a -> m b) -> m (a -> b)
.
Специализируйте m
в продолжение monad ((_ -> r) -> r)
(я опускаю новую оболочку).
transform :: forall a b r. (a -> (b -> r) -> r) -> ((a -> b) -> r) -> r
Специализировать r=a
:
transform :: forall a b. (a -> (b -> a) -> a) -> ((a -> b) -> a) -> a
Применить
transform const :: forall a b. ((a -> b) -> a) -> a
Изоморфизмом Карри-Говарда является интуиционистская тавтология
((A -> B) -> A) -> A
но это Закон Пирса, который не доказуется в интуиционистской логике. Противоречие.