Преобразование IO Int в Int - PullRequest
       47

Преобразование IO Int в Int

13 голосов
/ 21 ноября 2010

Я создал комбинированный список для преобразования xmlWidget в comboBox с помощью функции castTocomboBox, и теперь я хочу получить текст или индекс активного элемента. Проблема в том, что если я использую функцию comboBoxGetActive, она возвращает результат IO Int, и мне нужно знать, как я могу получить значение Int. Я пытался читать о монадах, чтобы понять, что можно делать в подобной ситуации, но я не понимаю. Я ценю всю помощь, которую я могу получить. Наверное, стоит упомянуть, что я использую Glade и gtk2hs.

Ответы [ 3 ]

27 голосов
/ 21 ноября 2010

Как правило, вы пишете что-то вроде этого:

do
   x <- somethingThatReturnsIO
   somethingElseThatReturnsIO $ pureFunction x

Нет способа вывести "Int" из "IO Int", кроме как сделать что-то еще в монаде IO.

В терминах монады приведенный выше код десугарсит в

somethingThatReturnsIO >>= (\x -> somethingElseThatReturnsIO $ pureFunction x)

Оператор ">> =" (произносится как "bind") делает магию преобразования "IO Int" в "Int", но отказывается передавать этот Int прямо вам. Это будет только передавать это значение в другую функцию в качестве аргумента, и эта функция должна возвращать другое значение в «IO». Медитируйте на тип привязки для монады IO в течение нескольких минут, и вы можете стать просветленным:

>>= :: IO a -> (a -> IO b) -> IO b

Первый аргумент - это ваше начальное значение IO Int, которое возвращает comboBoxGetActive. Вторая - это функция, которая принимает значение Int и превращает его в какое-то другое значение IO. Таким образом, вы можете обрабатывать Int, но результаты этого никогда не выходят из монады ввода / вывода.

(Конечно, есть печально известное «unsafePerformIO», но на своем уровне знаний вы можете быть уверены, что если вы используете его, то делаете это неправильно.)

(На самом деле десагеринг гораздо сложнее, чтобы учесть неудачные совпадения с образцами. Но вы можете притвориться, что я написал правду)

11 голосов
/ 21 ноября 2010

Ну, есть unsafePerformIO: http://haskell.org/ghc/docs/6.12.1/html/libraries/base-4.2.0.0/System-IO-Unsafe.html#v:unsafePerformIO

(Если вы хотите узнать, как найти этот метод: перейдите на http://www.haskell.org/hoogle и найдите нужную подпись здесь IO a -> a)

Тем не менее, вы, наверное, слышали о "Что происходит в IO, остается в IO".И для этого есть очень веских причин (просто прочитайте документацию по unsafePerformIO).Так что, скорее всего, у вас есть проблема с дизайном, но для того, чтобы получить помощь от опытных Хаскеллеров (я, конечно, нет), вам нужно описать вашу проблему более подробно.

3 голосов
/ 24 ноября 2010

Чтобы понять, что это за типы - шаг за шагом - сначала посмотрите, что такое Maybe и List:

data Maybe a = Nothing | Just a
data [a]     = [] | a : [a]

( Может быть ) - это другой тип, чем ( a ), например ( Возможно Int ), отличается от ( Int ).Примеры значений типа ( Может быть Int ): Всего 5 и Ничего .

Список ( a ).) s можно записать как ( [] a ) и как ( [a] ).Примерные значения ( [Int] ): [1,7,42] и [] .

Now, ( IO a ) также отличается от ( a ): это вычисление ввода / вывода, которое вычисляет значение типа ( a ).Другими словами: это скрипт или программа, которая должна быть выполнена для генерации значения типа ( a ).Пример ( IO String ) - getLine , который считывает строку текста из стандартного ввода.

Теперь тип comboBoxGetActive:

comboBoxGetActive :: ComboBoxClass self => self -> IO Int

Это означает, что comboBoxGetActive является функцией ( -> ), которая сопоставляется с любым типом, который имеет экземпляр класса типов ComboBoxClass (примитивные классы типов чем-то похожи на java-интерфейсы) к ( IO Int ).Каждый раз, когда эта функция ( -> ) оценивается с помощью одного и того же входного значения этого типа ( self ) (независимо от того, какой это тип), это приводит к одному и тому же значению:всегда одно и то же значение типа ( IO Int ), это означает, что это всегда один и тот же сценарий.Но когда вы выполняете тот же сценарий в разное время, он может выдавать разные значения типа ( Int ).

Основная функция вашей программы имеет тип ( IO ()), это означает, что компилятор и система времени выполнения оценивают уравнения, которые вы программируете на этом функциональном языке, в значение main, которое будет выполнено, как только вы запустите программу.

...